backtrack 回溯算法
先做决定,然后撤回 , 就是一个决策树的遍历
需要注意的有三个问题
- 
路径
 - 
选择
 - 
终止条件
伪码如下:
public void backtrack(路径,选择列表){ if (终止条件){ add(路径); return; } for 选择 in 列表 { 做选择; backtrack(路径,选择列表); 撤回; } } 
而且不管怎么优化,都符合回溯框架,而且时间复杂度都不可能低于 O(N!),因为穷举整棵决策树是无法避免的。这也是回溯算法的一个特点,不像动态规划存在重叠子问题可以优化,回溯算法就是纯暴力穷举,复杂度一般都很高
46. 全排列 题目要求不含重复数字,所以我们还需要注意不符合的选择
class Solution {
    public List<List<Integer>> res = new LinkedList<>();
    public List<List<Integer>> permute(int[] nums){
        LinkedList<Integer> track = new LinkedList<>();
        backtrack(nums , track);
        return res;
    }
    private void backtrack(int[] nums, LinkedList<Integer> track) {
        // 触发结束条件
        if (track.size() == nums.length) {
            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();
        }
    }
}
47. 全排列 II 而在47中,是包含了重复数字
class Solution {
    boolean[] record;
    List<List<Integer>> ans = new LinkedList<>();
    public List<List<Integer>> permuteUnique(int[] nums) {
        int n = nums.length;
        if (n == 0){
            return ans;
        }
        //剪枝前需排序
        Arrays.sort(nums);
        LinkedList<Integer> track = new LinkedList<>();
        record = new boolean[n];
        backtrack(nums , track);
        return ans;
    }
    private void backtrack(int[] nums , LinkedList<Integer> list){
        if (nums.length == list.size()){
            ans.add(new LinkedList<>(list));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            if (record[i]){
                continue;
            }
            //剪枝,!record[i - 1]为顺序剪枝,record[i - 1]为倒序剪枝
            if (i > 0 && nums[i] == nums[i - 1] && !record[i - 1]) {
                continue;
            }
            record[i] = true;
            list.add(nums[i]);
            backtrack(nums , list);
            record[i] = false;
            list.removeLast();
        }
    }
}