回溯算法
回溯的本质是穷举,穷举所有可能,然后选出我们想要的答案,如果想让回溯法高效一些,可以加一些剪枝的操作。
回溯法,一般可以解决如下几种问题:
1、组合问题:N个数里面按一定规则找出k个数的集合
2、切割问题:一个字符串按一定规则有几种切割方式
3、子集问题:一个N个数的集合里有多少符合条件的子集
4、排列问题:N个数按一定规则全排列,有几种排列方式
5、棋盘问题:N皇后,解数独等等
回溯法模版:
void backtracking(参数) {if (终止条件) {存放结果;return;}for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {处理节点;backtracking(路径,选择列表); // 递归回溯,撤销处理结果}
}
77. 组合
给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
示例: 输入: n = 4, k = 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]
根据模版,得出代码:
class Solution {
public:vector<vector<int>> res;vector<int> path;void backtravel(int n,int k,int start){if(path.size()==k){res.push_back(path);return;}for(int i=start;i<=n;++i){path.push_back(i);//处理节点backtravel(n,k,i+1);//递归path.pop_back();//回溯}}vector<vector<int>> combine(int n, int k) {backtravel(n,k,1);return res;}
};
配合剪枝操作进行优化:如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了。所以起始位值至多从n-(k-path.size())+1开始。
class Solution {
public:vector<vector<int>> res;vector<int> path;void backtravel(int n,int k,int start){if(path.size()==k){res.push_back(path);return;}for(int i=start;i<=n-(k-path.size())+1;++i){path.push_back(i);//处理节点backtravel(n,k,i+1);//递归path.pop_back();//回溯}}vector<vector<int>> combine(int n, int k) {backtravel(n,k,1);return res;}
};
216.组合总和III
找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
说明:
- 所有数字都是正整数。
- 解集不能包含重复的组合。
示例 1: 输入: k = 3, n = 7 输出: [[1,2,4]]
示例 2: 输入: k = 3, n = 9 输出: [[1,2,6], [1,3,5], [2,3,4]]
class Solution {
public:vector<vector<int>> res;vector<int> path;void backtravel(int k,int n,int sum,int start){if(path.size()==k&&sum==n){res.push_back(path); return; }for(int i=start;i<=9;++i){sum+=i;path.push_back(i);backtravel(k,n,sum,i+1);path.pop_back();sum-=i;}}vector<vector<int>> combinationSum3(int k, int n) {backtravel(k,n,0,1);return res;}
};
17.电话号码的字母组合
给定一个仅包含数字
2-9
的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例 1:
输入:digits = "23" 输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
回溯法来解决n个for循环的问题,因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合。
class Solution {
public:const string letterMap[10] = {"", // 0"", // 1"abc", // 2"def", // 3"ghi", // 4"jkl", // 5"mno", // 6"pqrs", // 7"tuv", // 8"wxyz", // 9};vector<string> res;void backtravel(string digits,int idx,string s){if(idx==digits.size()){res.push_back(s);return;}int digit=digits[idx]-'0';string letter=letterMap[digit];for(int i=0;i<letter.size();++i){backtravel(digits,idx+1,s+letter[i]);}}vector<string> letterCombinations(string digits) {if(digits.size()==0) return res;backtravel(digits,0,"");return res;}
};