回溯算法篇-01:全排列

力扣46:全排列

回溯算法篇-01:全排列_第1张图片

题目分析

这道题属于上一篇——“回溯算法解题框架与思路”中的 “元素不重复不可复用” 那一类中的 排列类问题。

我们来回顾一下当时是怎么说的:

排列和组合的区别在于,排列对“顺序”有要求。比如 [1,2] 和 [2,1] 是两个不同的结果。

这就导致了同一个元素 在同一条路径中不可重复使用,在不同的路径中可以重复使用。 

比如数组 [1,2,3] ,在第一条路径 [1,2,3]中,1只能出现一次。但是在另一条选择路径 [2,1,3] 中,1或者在其他路径中出现过的元素仍然可以继续使用。

为了保证 “同一元素在一条路径中只能使用一次” ,我们需要额外维护一个boolean数组用于记录元素的使用情况:已经使用过的元素标记为 “true” ,没有使用过的元素标记为 “false”;

套用框架:

回溯算法篇-01:全排列_第2张图片

class Solution {
    //用于存放子结果的容器
    List> res = new LinkedList<>();
    public List> permute(int[] nums) {
        //存放路径的容器
        LinkedList track = new LinkedList<>();
        //用于记录元素使用情况的boolean数组
        //数组初始值全为false,意为“该元素尚未使用”
        boolean[] used = new boolean[nums.length];
        backtrack(nums,track,used);
        return res;
    }
    //backtrack函数参数选用:函数参数设置时只需要看看这个函数想达到目的
    //需要那些参数,然后把这些参数全丢尽括号中就好了
    void backtrack(int[] nums,LinkedList track,
        boolean[] used){
        //终止条件:当子集收集满后放入最终解集中
        if(track.size() == nums.length){
            res.add(new LinkedList(track));
            return;
        }
        //遍历选择列表
        for(int i = 0;i < nums.length;i++){
            //如果这个元素已经使用过了,就跳过这个选择
            if(used[i]){
                continue;
            }
            //做选择
            track.add(nums[i]);
            //更新元素使用情况——“已使用”
            used[i] = true;
            //进入下一层决策
            backtrack(nums,track,used);
            //撤销选择
            track.removeLast();
            //更新元素使用情况——“未使用”
            used[i] = false;
        }
    }
}

总结

在排列问题中,为了防止出现重复结果,我们会维护一个boolean数组来记录元素的使用情况。

与 组合/子集 类问题相比,排列类问题在进入下一层决策时并没有将起始元素下标后移一位。这样就不会影响到选择列表。

比如对于数组[1,2,3],假如一条路径是从 2 开始的,那么进入下一层决策树时,选择列表仍然是 [1,2,3]。

而对比与 组合/子集 类问题,此时他们的选择列表就只有 [3] 了。

你可能感兴趣的:(手把手带你刷力扣Hot100,算法)