题目
题目来源:力扣(LeetCode)
给定一个可包含重复数字的序列 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]]
思路分析
回溯
- 先对数组进行升序排序,以保证相同的数字相邻
- 然后从左到右遍历数组,如果当前数字和前一个相同,即nums[i] == nums[i - 1],当前数字已经被选过,则直接跳过当前数字
/**
* @param {number[]} nums
* @return {number[][]}
*/
var permuteUnique = function (nums) {
let res = [];
let len = nums.length
// 对数组进行升序排序,保证相同的数字都相邻
nums.sort((a, b) => a - b)
unique([], 0)
return res
function unique(arr) {
// 个数选够了,将当前排列加入结果中
if (arr.length == len) {
res.push([...arr])
return
}
// 枚举出所有的选择
for (let i = 0; i < nums.length; i++) {
// 跳过,避免产生重复的排列
if (nums[i] == nums[i - 1]) continue
// 将当前的数字加入排列中
arr.push(nums[i])
// 由于当前数字已经加入排列中,因此将当前数字从nums数组中删除
// 直接将当前已选择的数字从原数组中删除或重新加入,减少了额外定义变量来记录当前数字是否已被选择
nums.splice(i, 1)
// 基于已选的数字,递归继续选择未选的数字
unique(arr)
// 从 排列中撤销当前选择的数字,并将当前数字重新放回nums数组中,这一步是回溯
nums.splice(i, 0, arr.pop())
}
}
};