本文已参与「新人创作礼」活动,一起开启掘金创作之路。
题目
给定一个可包含重复数字的序列 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
};