原文:47. 全排列 II(力扣 面试题) - 每天一个JavaScript小知识@Js中文网 · 码农进阶题库

原文地址:https://www.javascriptc.com/interview-tips/zh_cn/leetcode/leetcode-javascript-solution-047/

题目:

难度:Middle

相关话题:回溯算法

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

示例:

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

思路:

稍微复杂一点的回溯,主要用到了处理重复的方法,先排序,排序是为了能高效的处理重复,而不必使用hash检查是否重复。

排序后,例如[1,1,2,2,3],如果我第一位是1(索引0),已经做好了排列,那么下一次第一位是1(索引1)就不需要再次计算排列了, 因为已经重复了。

因此处理重复条件之一:i>0 && nums[i-1]===nums[i],但是还不够,如果我现在第一位是2,那么第二位是1(索引1)应该是合理的, 但却和这个条件冲突了。

因此完整条件应该是if(i>0 && nums[i-1]===nums[i] && !used[i-1])continue,为什么上一位没使用就可以跳过呢?

在我们第一次计算重复的时候,上一位一定是使用了,而当我们第二次计算重复值时,上一位是未使用的,因此可以正确避免重复的排列。

/**
 * @来源: Javascript中文网 - 前端进阶资源教程 https://www.javascriptc.com/
 * @介绍:一个致力于帮助开发者用代码改变世界为使命的平台,每天都可以在这里找到技术世界的头条内容
 * @param {number[]} nums
 * @return {number[][]}
 */
var permuteUnique = function(nums) {
    let result=[],temp=[],aux=[]
    nums.sort()
    backtrack(result,temp,nums,aux)
    return result
    function backtrack(result,temp,nums,aux){
        if(aux.length===nums.length){
            result.push(aux.slice())
        }
        for(let i=0;i<nums.length;i++){
            if(temp[i] || (i>0 && nums[i]===nums[i-1] && !temp[i-1] ))continue
            temp[i]=true
            aux.push(nums[i])
            backtrack(result,temp,nums,aux)
            temp[i]=false
            aux.pop()
        }
    }
};

扩展阅读: