leetcode-47-全排列 II

2,468 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第28天,点击查看活动详情

题目地址

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

示例 1:

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

示例 2:

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

提示:

  • 1 <= nums.length <= 8
  • -10 <= nums[i] <= 10

解题思路

本题和 leetcode-46-全排列类似,只不过可能包含重复的数字,并要求返回结果不含有重复的全排列。
首先我们思考,数组中只有一个元素([1])的时候,全排列就只有 1 种([[1]]):
数组中有两个元素([1,2])的时候,全排列有 2 种([[1,2],[2,1]]);
数组中有三个元素([1,2,3])的时候,全排列有 6 种([[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]])。
观察上面的结果可发现,全排列分别以每一个元素为第一个,然后以剩余的每一个元素为第二个,然后以剩余的每一个元素为第三个,以此类推...
很明显,每次选择一个剩余元素作为下一个元素的逻辑是相同的,所以本题可以通过递归解题。
递归函数接收两个参数(nums, arr) ,分别是待选择元素的数组和已选择元素的结果数组,每次遍历带选择数组,选取每一个作为下一个元素并递归调用该函数。递归函数的退出条件为 nums.length === 0,此时说明带选择元素的数组为空,找到了一个新的全排列,将其插入到结果数组即可。
以上和 leetcode-46-全排列 解题思路一致,问题是本题需要去重,我们想,如果有两个数字 2,以第一个 2 和第二个 2 作为某一个位置的元素,得到的排列组合必然是相同的,所以可以首先对输入数组进行排序,遍历过程中判断如果当前数字和前一个相同,跳过当前循环。

代码实现

var permuteUnique = function(nums) {
    const res = []
    nums.sort((a,b) => a-b)

    function getRes(nums,arr){
        if(nums.length===0){
            res.push(arr)
            return;
        }
        for(let i = 0;i<nums.length;i++){
            if(i>0 && nums[i] === nums[i-1]){
                continue
            }

            const _nums = [...nums]
            const _arr = [...arr]
            _arr.push([_nums.splice(i,1)])
            getRes(_nums,_arr)
        }
    }
    getRes(nums,[])

    return res
}

至此我们就完成了 leetcode-47-全排列 II

如有任何问题或建议,欢迎留言讨论!