回溯算法一般用于对数据枚举后选取符合条件的结果并最终返回结果集的问题,之所以叫回溯法,是因为它可进可退
要想理解回溯的本质,还是要通过具体的题目去学习。
路径问题
https://www.nowcoder.com/practice/b736e784e3e34731af99065031301bca?
tpId=13&tqId=11177&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
分析:
由图可以知道这里需要采取深度优先遍历(DFS)的方式先找到一个叶子节点。
void _FindPath(TreeNode* root,int target,vector<vector<int>>&
result,vector<int>& tmp){ //不要忘记引用
//第五步,设置结束条件
if(root==nullptr)
return;
//第一步,将当前节点值放入tmp
tmp.push_back(root->val);
target-=root->val;
if(root->left==root->right && target==0)//条件判断
result.push_back(tmp);
//第二步,访问左树(子问题)
_FIndPath(root->right,target,result,tmp);
//本条语句执行完,代表左树的所有路径均已检测完
//第三步,访问右树(子问题)
_FindPath(root->right,target,result,tmp);
//本条语句执行完,代表右树的所有路径均已检测完
//第四步,回退
tmp.pop_back();
}
vector<vector<int> > FindPath(TreeNode* root, int target) {
vector<vector<int>> result;
if(root==nullptr)
return result;
vector<int> tmp;
//需要一个临时变量来存放检测中的路径
_FindPath(root,target,result,tmp);
return result;
}
全排列问题
https://www.nowcoder.com/practice/fe6b651b66ae47d7acce78ffdd9a96c7?
tpId=13&tqId=11180&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串 abc,acb,bac,bca,cab ,cba
分析:
bool IsExist(vector<string>& res,string& str,map<string,int>& Map){
if(Map[str]==1){
return true;
}
return false;
}
void _Permutation(vector<string>& res,string& str,int
start,map<string,int>& Map){
//结束条件
if(start==str.length()-1){
if(!IsExist(res,str,Map)){
res.push_back(str);
Map[str]=1;}
return;
}
for(int i=start;i<str.length();++i){
swap(str[start],str[i]);
//让每一个元素都当一次首
_Permutation(res,str,start+1,Map);
//子问题:求首元素之后元素的排列组合
swap(str[start],str[i]);
//回退
}
vector<string> Permutation(string str) {
vector<string> res;
if(str==""){
res.push_back(str);
}
map<string,int> Map;
//需要一张映射表来方便后续去重
_Permutation(res,str,0,Map);
return res;
}