持续创作,加速成长!这是我参与「掘金日新计划 · 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
如有任何问题或建议,欢迎留言讨论!