1.组合
(1)模板
void backtracking(参数) {if (终止条件) {存放结果;return;}for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {处理节点;backtracking(路径,选择列表); // 递归回溯,撤销处理结果}
}
重要参数,List<List<Integer>> res ,Deque<Integer> path, int startIndex
class Solution {List<List<Integer>> res = new ArrayList<>();Deque<Integer> path = new ArrayDeque<>();public List<List<Integer>> combine(int n, int k) {backtrack(n, 1, k);return res;}// startIndex 就是防止出现重复的组合private void backtrack(int n, int startIndex, int k) {if (path.size() == k) {// path路径中存放的数达到k个即放入结果res.add(new ArrayList<>(path));return;}for (int i = startIndex; i <= n; i++) { // 范围 [1, n] path.add(i);backtrack(n, i + 1, k);path.removeLast();}}
}
(2)优化剪枝,主要是对选过的数字进行剪除
for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) // i为本次搜索的起始位置
2.组合总和III
回溯算法处理,sum来统计path里元素的总和,处理过程 和 回溯过程是一一对应的,处理有加,回溯就要有减! for循环内一个是sum的变化,一个是path的变化
class Solution {List<List<Integer>> res = new ArrayList<>();Deque<Integer> path = new ArrayDeque<>();public List<List<Integer>> combinationSum3(int k, int n) {backtrack(k, n, 1, 0);return res;}private void backtrack(int k, int targetsum, int startIndex, int sum) {if (path.size() == k) {if (sum == targetsum) res.add(new ArrayList<>(path));return;}for (int i = startIndex; i <= 9; i++) {sum += i;path.add(i);backtrack(k, targetsum, i + 1, sum);sum -= i;path.removeLast();}}
}
3.电话号码的数字组合
对字符串的回溯可以用StringBuilder来处理
停止条件 {
res.add(path.toString());
}
for循环内 {
path.append(str.charAt(i));
dfs(digits, dept + 1);// 递归
path.deleteCharAt(dept);// 回溯
}
class Solution {List<String> res = new ArrayList<>();//定义一个返回的结果集StringBuilder path = new StringBuilder();//定义一个存储路径的可变字符的变量Map<Character,String> map = new HashMap<>(){{//定义哈希表表示字符串的所有可能put('2', "abc");put('3', "def");put('4', "ghi");put('5', "jkl");put('6', "mno");put('7', "pqrs");put('8', "tuv");put('9', "wxyz");}};public List<String> letterCombinations(String digits) { if(digits.length() == 0) {return res;}dfs(digits, 0);return res;}public void dfs(String digits, int dept) {// 停止条件:当递归到底层的时候,将路径上的参数加入结果集中 if (dept == digits.length()) {res.add(path.toString());return;} else {//定义一个存储字符串的数字char digit = digits.charAt(dept);//定义一个存储数字对应的所有可能字符串String str = map.get(digit);int len = str.length();// 遍历字符串for (int i = 0; i < len; i++) {path.append(str.charAt(i));dfs(digits, dept + 1);// 递归path.deleteCharAt(dept);// 回溯}}}
}