题目
思路
这里我主要讲的是回溯法的做法。
回溯主要是基于递归的思想,一定要记得,在递归结束后,要撤销选择。在递归之前做出选择,在递归之后撤销刚才的选择,就能正确得到每个节点的选择列表和路径。
大体框架如下:
def backtrack(选择列表,路径):
if 满足结束条件:
操作res
return
for 选择 in 选择列表:
if 选择不合法
# 剪枝
continue
# 做选择 进入下一层决策树
选择列表.remove(选择)
路径.add(选择)
backtrack(选择列表,路径)
# 撤销选择
路径.remove(选择)
借用labuladong公众号的一张图来帮助理解一下,这道题的过程大概如下。
代码
import java.util.*;
public class Solution {
List<List<Integer>> res = new LinkedList<>();
public List<List<Integer>> permute(int[] nums) {
if (nums.length == 0) {
return res;
}
// 记录「路径」
LinkedList<Integer> track = new LinkedList<>();
backtrack(nums, track);
return res;
}
// 路径:记录在 track 中
// 选择列表:nums 中不存在于 track 的那些元素
// 结束条件:nums 中的元素全都在 track 中出现
void backtrack(int[] nums, LinkedList<Integer> track) {
// 触发结束条件
if (track.size() == nums.length) {
// 注意这里要new一个 放入的将会变成引用
res.add(new LinkedList(track));
return;
}
for(int i=0; i< nums.length; i++){
// 剪去不合法的分支
if(track.contains(nums[i])){
continue;
}
// 做选择
track.add(nums[i]);
// 进入下一层决策树
backtrack(nums, track);
// 取消选择
track.removeLast();
}
}
}
结语
当然就这道题而言,还有很多更优秀的解法,比如dfs、bfs搭配visited等方法剪枝,这些我以后会争取多做些笔记。
比较适用回溯算法的题还有这些,冲冲冲。
参考资料
我的leetcode刷题历程是跟着labuladong大佬混的,没错,就是那个leetcode上一出题解,必属精品的那位。