//未剪枝 // class Solution { // List<List<Integer>> result = new ArrayList<>();//存放符合条件结果的集合 // List<Integer> path = new ArrayList<>();//存放符合条件的结果 // public List<List<Integer>> combine(int n, int k) { // backtracking(n, k, 1); // return result; // }
// private void backtracking(int n, int k, int startIndex){ // if(path.size() == k){ //终止条件 // result.add(new ArrayList<>(path));//存放结果 // return; // } // for(int i = startIndex; i <= n; i++){//选择本层集合中的元素 // path.add(i);//处理节点 // backtracking(n, k, i + 1);//递归 // path.removeLast();//回溯撤销处理的节点 // } // } // }
//剪枝 classSolution { List<List<Integer>> result = newArrayList<>();//存放符合条件结果的集合 List<Integer> path = newArrayList<>();//存放符合条件的结果 public List<List<Integer>> combine(int n, int k) { backtracking(n, k, 1); return result; }
privatevoidbacktracking(int n, int k, int startIndex){ //可剪枝处 if(path.size() == k){ //终止条件 result.add(newArrayList<>(path));//存放结果 return; } /** 如果for循环选择的起始位置之后的元素个数已经不足我们需要的元素个数那就没有必要搜索了 已经选择的元素path.size() 还需要选择的元素k - path.size() 在集合中至多要从n - (k - path.size()) + 1开始遍历 */ for(inti= startIndex; i <= n - (k - path.size()) + 1; i++){//选择本层集合中的元素 path.add(i);//处理节点 backtracking(n, k, i + 1);//递归 path.removeLast();//回溯撤销处理的节点 } } }
回溯搜索的话从区间1~9取数,向组合中添加数字,累计当前的总和。 在递归过程中,如果组合的长度达到了 k 且组合的和等于 n,则该组合为有效结果,加入到结果集中。如果组合长度超过 k,或者当前数字的和已经超过 n,则不需要继续递归,进行回溯。每次递归时尝试选择数字,之后在递归返回时将该数字移除(即回溯),以便尝试其他可能性🤔🤔🤔
我们来进一步梳理回溯三要素
递归函数的参数和返回值
1 2 3 4 5
//定义结果集和组合的全局变量,减少递归参数 List<List<Integer>> result = newArrayList<>(); List<Integer> path = newArrayList<>(); //回溯搜索所需的数字索引、目标和n、组合长度k privatevoidbacktracking(int k, int n, int startIndex){}