持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第15天,点击查看活动详情
每日刷题 2022.10.13
- leetcode原题链接:leetcode.cn/problems/ta…
- 难度:困难
题目
- 给定一个可包含重复数字的序列
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
解题思路
- 与
剑指 Offer II 083. 没有重复元素集合的全排列
思路有些类似 - 只不过在
DFS
处理全排列的过程中(for
循环内)需要用一个Set
集合来存放已经交换过的重复元素,即不让当前的nums[i]
与一个等值的已经交换过的元素再进行交换; - 例如:对
[2,1,1]
操作,只会将2
与第一个1
进行交换,不会与第二个1
交换。因为第一个元素与第二个元素交换后变成[1,2,1]
,进入下一层递归会得到[1,2,1]
与[1,1,2]
两种结果,加上原本的排列共有三种,刚好符合答案。 - 用
unordered_set
也可以,但会消耗更多内存,因为散列表为了实现O(1)
时间复杂度的查找,会开得比所需空间要大,而set
底层是红黑树,需要多大的空间就占用多大,不过查找效率是O(logN)
。
代码
/**
* @param {number[]} nums
* @return {number[][]}
*/
var permuteUnique = function(nums) {
let ans = [], chosen = [], n = nums.length, map = new Map();
for(let i = 0; i < n; i++) {
map.set(nums[i], (map.get(nums[i]) || 0) + 1);
}
function dfs (idx, nums) {
if(idx == n){
// 去重
ans.push([...chosen]);
return;
}
// 单层的逻辑
let set = new Set();
for(let i = 0; i < n; i++) {
if(map.get(nums[i]) != 0 && !set.has(nums[i])){
// 如果当前的元素可以放在当前的位置上
// 那么就执行操作
set.add(nums[i])
chosen.push(nums[i]);
map.set(nums[i], map.get(nums[i]) - 1);
console.log('set',i,set)
dfs(idx + 1, nums);
map.set(nums[i], map.get(nums[i]) + 1)
chosen.pop();
}
}
}
dfs(0, nums);
return ans;
};