什么是回溯算法
回溯算法是⼀种经典的递归算法,通常⽤于解决组合问题、排列问题和搜索问题等。
回溯算法的基本思想:从⼀个初始状态开始,按照⼀定的规则向前搜索,当搜索到某个状态⽆法前进时,回退到前⼀个状态,再按照其他的规则搜索。回溯算法在搜索过程中维护⼀个状态树,通过遍历状态树来实现对所有可能解的搜索。
回溯算法的核心思想:“试错”,即在搜索过程中不断地做出选择,如果选择正确,则继续向前搜索;否则,回退到上⼀个状态,重新做出选择。回溯算法通常⽤于解决具有多个解,且每个解都需要搜索才能找到的问题。
总结
回溯算法是⼀种⾮常重要的算法,可以解决许多组合问题、排列问题和搜索问题等。回溯算法的核⼼思想是搜索状态树,通过遍历状态树来实现对所有可能解的搜索。回溯算法的模板⾮常简单,但是实现起来需要注意⼀些细节,⽐如如何做出选择、如何撤销选择等。
1.全排列
题目解析
算法原理
代码
class Solution {
List<List<Integer>> ret;
List<Integer> path;
boolean[] check;
public List<List<Integer>> permute(int[] nums) {
ret = new ArrayList<>();
path = new ArrayList<>();
check = new boolean[nums.length];
dfs(nums);
return ret;
}
public void dfs(int[] nums) {
if (nums.length == path.size()) {
ret.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < nums.length; i++) {
if (check[i] == false) {
path.add(nums[i]);
check[i] = true;
dfs(nums);
// 回溯 -> 恢复现场
check[i] = false;
path.remove(path.size() - 1);
}
}
}
}
2.子集
题目解析
算法原理
解法一:
只有叶子节点是想要的结果
解法二:
每一个节点都是结果
代码
// 解法⼀:
class Solution {
List<List<Integer>> ret;
List<Integer> path;
public List<List<Integer>> subsets(int[] nums) {
ret = new ArrayList<>();
path = new ArrayList<>();
dfs(nums, 0);
return ret;
}
public void dfs(int[] nums, int pos) {
if (pos == nums.length) {
ret.add(new ArrayList<>(path));
return;
}
// 选
path.add(nums[pos]);
dfs(nums, pos + 1);
path.remove(path.size() - 1); // 恢复现场
// 不选
dfs(nums, pos + 1);
}
}
// 解法⼆:
class Solution {
List<List<Integer>> ret;
List<Integer> path;
public List<List<Integer>> subsets(int[] nums) {
ret = new ArrayList<>();
path = new ArrayList<>();
dfs(nums, 0);
return ret;
}
public void dfs(int[] nums, int pos) {
ret.add(new ArrayList<>(path));
for (int i = pos; i < nums.length; i++) {
path.add(nums[i]);
dfs(nums, i + 1);
path.remove(path.size() - 1); // 恢复现场
}
}
}