Day22 回溯算法_part01
参考文章:代码随想录
77. 组合 - 力扣(LeetCode)
通过递归函数实现回溯法,这里需要在递归函数外额外设置一个数组path储存每次符合要求的结果,和一个二维数组result储存最终结果,设为全局变量。
向递归函数中传入n、k和一个为int型变量startIndex,这个参数用来记录本层递归的中,集合从哪里开始遍历(集合就是[1,...,n] ),防止出现重复的组合。
进入函数首先判断当前组和是否已满,即path的大小是否等于k。如果等于k则说明已找到一个符合要求的组合,直接将path整个压入result中并返回。
如果不等于k则说明还没有找齐一个大小为k的组合,用for循环从startIndex标记的位置开始遍历集合的剩余部分,进入循环首先将当前i的值加入path中,再对集合从i+1开始的部分递归调用回溯函数;到这一步说明i的组合已经遍历完了,对path执行pop弹出i,一次循环结束。
class Solution {
public:vector<vector<int>> result;vector<int> path;void backtracking(int n,int k,int startIndex){if(path.size()==k){result.push_back(path);return;}for(int i=startIndex;i<=n;i++){path.push_back(i);backtracking(n,k,i+1);path.pop_back();}}vector<vector<int>> combine(int n, int k) {backtracking(n,k,1);return result;}
};
注意循环的判断条件是i<=n,因为组合最后是可以取到n的。
216. 组合总和 III - 力扣(LeetCode)
本题就是在[1,2,3,4,5,6,7,8,9]这个集合中找到和为n的k个数的组合。
思路和上一题基本一样,就是多了一个对总和大小的要求。这里的k还是组合的大小,n不再是搜索范围,而是组合的总和值,搜索范围变为固定的[1,9]。
同样需要在递归函数外额外设置一个数组path储存每次符合要求的结果,和一个二维数组result储存最终结果,设为全局变量。向递归函数中传入n、k、start index和当前总和sum。进入递归函数首先判断path大小是否已经为k,如果大小等于k说明找到一个大小符合条件的组合判断当前总和是否为n,如果为n说明该组合完全符合条件存入结果数组reuslt中;然后return返回。注意这里如果大小符合而条件不符则是直接返回不存入结果数组。
如果当前path大小不为k说明还没找齐k个元素的组合,同样用for循环从startIndex开始遍历[1,9]的集合。将当前i压入path后要多一步将sum值加上i,再对集合从i+1开始的部分递归调用回溯函数。最后把i从path弹出,再将sum减去i的值,完成一次循环。
class Solution {
public:vector<vector<int>> result;vector<int> path;void backtracking(int n,int k,int startIndex,int sum){if(path.size()==k){if(sum==n) result.push_back(path);return;}for(int i=startIndex;i<=9;i++){path.push_back(i);sum+=i;backtracking(n,k,i+1,sum);sum-=i;path.pop_back();}}vector<vector<int>> combinationSum3(int k, int n) {backtracking(n,k,1,0);return result;}
};
17. 电话号码的字母组合 - 力扣(LeetCode)
额外设置一个字符串数组储存数字和字母之间的对应关系,注意不要遗漏0和1:
const string letterMap[10] = {"", // 0"", // 1"abc", // 2"def", // 3"ghi", // 4"jkl", // 5"mno", // 6"pqrs", // 7"tuv", // 8"wxyz", // 9};
函数外定义储存最终结果的字符串数组result,和储存每个独立结果的字符串s。
用递归函数实现回溯法,向递归函数中传入输入的数字串digits(以字符串格式给出)指针,和用来记录遍历到digits第几个数字的标签index。
进入递归函数首先判断当前index是否已经指向digits最后一个元素,即index==digits.size(),如果是,则说明已将当前数字串对应字母找齐,直接将s压入结果数组并返回。
如果index还没有指向最后,说明当前数字串还没有找齐。将数字串digits中index指向的值转换为int类型赋值给digit,并根据letterMap找到对应的字符存赋值给letters,这样就实现了从数字到字符串的转换。
今下来进入for循环,循环处理letters中的每一个值。for循环从0遍历letters,每遍历到一个值就将letters[i]压入字符串s中,然后对数字串digits从index+1开始的部分继续递归调用回溯函数。执行到这一步说明字母letters[i]的组合找完了,对s进行pop结束本次循环。
class Solution {
public:string lettermap[10]={"", // 0"", // 1"abc", // 2"def", // 3"ghi", // 4"jkl", // 5"mno", // 6"pqrs", // 7"tuv", // 8"wxyz", // 9};vector<string> result;string s;void backtracking(string& digits,int index){if(index==digits.size()){result.push_back(s);return;}int digit=digits[index]-'0';string letters=lettermap[digit];for(int i=0;i<letters.size();i++){s.push_back(letters[i]);backtracking(digits,index+1);s.pop_back();}}vector<string> letterCombinations(string digits) {if(digits.size()==0)return result;backtracking(digits,0);return result;}
};
注意这道题的result是字符串类型的一维数组了。