前端算法(40)

42 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

题目

给定一个可包含重复数字的序列 nums ,按任意顺序返回所有不重复的全排列。

输入: nums = [1,1,2]
输出:
[[1,1,2],
 [1,2,1],
 [2,1,1]]

题目解析

思路一

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permuteUnique = function(nums) {
    var res=[]
    // 先排序
    nums=nums.sort((a,b)=>a-b);
    // 声明一个数组:每个位置代表该位置元素是否被访问过
    var used=new Array(nums.length).fill(0)
    backtrack(nums,[],used);
    return res;
    function backtrack(nums,path,used){
        // 结束条件
        if(path.length==nums.length){
            res.push(path.slice(0));
            return;
        }
        for(var i=0;i<nums.length;i++){
            // 被访问过,直接下一个循环
            if(used[i]==1)continue;
            // 如果当前元素和前一个元素相等,并且前一个元素被访问过
            if(i>0 && nums[i]==nums[i-1] && used[i-1]==1){
                continue;
            }
            path.push(nums[i]);
            // 访问过标志为1
            used[i]=1;
            backtrack(nums,path,used)
            path.pop()
            // 弹出后标志为0
            used[i]=0;
        }
    }
};

思路二

我们在外层保存一个长度 N 的数组,数组的值表示 nums 已经被使用的情况,其中 1 表示已经被使用过 使用回溯的方式不断为临时数组temp 添加值,每一次迭代的时候从参考 visited,将被使用过的值剪掉 注意的是,如果是回溯回来的值,要保证下一次迭代的值和回溯回来的值不一样,防止重复获取,所以需要做 nums[i] === nums[i-1] && !visited[i-1] 判断,最后进行返回

var permuteUnique = function(nums) {
    const len = nums.length
    const ret = []
    const visited = new Array(len).fill(0) // 用来保存已经记录到临时数组的下标值,下标为 1 代表已经用了
    nums.sort((a,b) => a-b) // 排序,,防止在回溯的时候在相同的位置注入一样的值,导致重复排列的出现
    const recursion = (temp) => {
        if(temp.length === len) {
            ret.push(temp);
            return 
        }
        for(let i=0;i<len;i++){
            // 下标值已经取了,值在 temp 里了
            if(visited[i]) continue 
            // 如果当前值和上一个值相等且 visited 中没有上一个值的下标 i-1,证明当前状态是回溯回来后,去掉上一个 i-1 值,继续往下取的情况
            // 这个时候就需要去重,防止临时数组的当前值重复取
            if(nums[i] === nums[i-1] && !visited[i-1]) continue 
            visited[i] = 1
            recursion([...temp,nums[i]])
            visited[i] = 0 // 回溯回来之后,将下标去掉
        }
    }
    recursion([])
    return ret
};