回溯算法的一般可以解决的问题:
- 组合问题:如 LeetCode-77-组合、LeetCode-39-组合总和、LeetCode-40-组合总和Ⅱ、LeetCode-216-组合总和Ⅱ、LeetCode-17-电话号码的字母组合
- 分割问题:如 LeetCode-131-分割回文串、LeetCode-93-复原IP地址
- 子集问题:如 LeetCode-78-子集、LeetCode-90-子集Ⅱ、LeetCode-491-递增子序列
- 排列问题:如 LeetCode-46-全排列、LeetCode-46-全排列Ⅱ
- 棋盘问题:如 LeetCode-51-N皇后、LeetCode-37-解数读
递归三部曲:
① 确定递归函数的参数和返回值;一般是 void,名字一般是 backtracking
② 确定终止条件;
③ 确定单层递归逻辑。
LeetCode-77-组合 解题思路:
- 确定递归函数的参数,需要 n, k, 还有一个变化的下标startIndex
- 确定终止条件,这个简单,当一维数组的长度等于 k ,说明已经够了,停止即可;
- 确定单层递归逻辑,这个需要考虑从哪里开始判断,题目中是从1开始,所以下标也从1 开始,在for循环里开始回溯,但是每次回溯后为了方便将下一个元素加进去,也就是回到树形结构的父节点,我们需要弹出一个元素,这个容易忽略。
代码实现
java
class Solution {
/**
* @param n 1~n
* @param k 要求的个数
* @return 返回范围 [1, n] 中所有可能的 k 个数的组合
*/
public List<List<Integer>> combine(int n, int k) {
backtracking(n,k,1);
return res;
}
List<List<Integer>> res = new ArrayList<>();//二维数组,要返回的结果
List<Integer> path = new ArrayList<>();// 树形结构走的路径,即能放进去的数
public void backtracking(int n, int k, int startIndex){
if (path.size() == k){// 终止条件
res.add(new ArrayList<>(path));// 满足条件,将一维数组加到结果集中
return;// 切记需要返回
}
for (int i = startIndex; i <= n; i++) {// 没有剪枝的情况
path.add(i);
backtracking(n,k,i+1);// 回溯
path.remove(path.size()-1);// 还需要弹出一个元素,即表示回到上一步
}
}
}