回溯法 Backtracking
- 题目特征:遍历,找出所有可能的组合;分步,每一步有不同选择。
- 回溯意义:对所有节点进行尝试,添加当前节点到路径中,当前节点处理完成后,删除当前节点,返回上一步状态。
- 深度优先遍历(Depth-First-Search,DFS):尽可能深地搜索,遍历。
- 方法要点:结束条件、遍历、剪枝、选择路径、递归、删除路径。
- 缺点:暴力穷举,复杂度高
- 题目:
框架说明
- ret 返回结果,包括多条符合条件的路径
- track 路径,进行添加节点和删除节点的操作,满足条件的路径加入ret
- dfs(track, candidates, ...) 递归函数,核心
- 结束条件:判断当前路径是否搜索到最后一个节点,如果到达叶子节点,判断当前路径是否满足要求,满足则添加
- for()循环,在已有路径的基础上,遍历下一步的节点
- 剪枝:提前跳过明显不满足的节点
- 添加当前节点到路径中
- 递归,对添加当前节点后的路径进行操作
- 删除当前节点,返回上一步
模板
java:
class Solution {
// 保存结果
List<List<Integer>> ret = new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
int n = nums.length;
// 回溯法,保存路径
List<Integer> track = new ArrayList<>();
def(nums, track);
return ret;
}
public void def(int[] nums, List<Integer> track) {
// 停止条件
if (track.size() == nums.length) {
ret.add(new ArrayList<>(track));
}
for (int i = 0; i < nums.length; i++) {
// 剪枝
if (track.contains(nums[i])) {
continue;
}
// 加入路径
track.add(nums[i]);
// 递归
def(nums, track);
// 回退路径
track.remove(track.size() - 1);
}
}
}
C++:
// 回溯模板
class Solution {
private:
vector<vector<int>> ret; // 保存结果
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<int> track; // 保存路径
dfs(track, cadidates, target); // 定义回溯函数
return ret;
}
void dfs(vector<int> track, vector<int>& candidates, int target) {
// 结束条件
if () {
ret.push_back(track);
return;
}
// 遍历
for (int i = 0; i < candidates.size(); i++) {
// 剪枝
if () {
continue;
}
// 选择路径
track.push_back();
// 递归
dfs();
// 回溯状态
track.pop_back();
}
}
};