给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
解题思路
这个问题和之前的问题Leetcode 46:全排列(最详细的解法!!!)很类似。因为这个问题中包含重复元素,所以一个简单的处理方法是,先将输入的nums
排序,这样重复元素就会到一块。我们采用递归回溯的思想就可以解决。
class Solution:
def _permuteUnique(self, nums, used, p, result):
if len(p) == len(nums):
result.append(p.copy())
return
for i,_ in enumerate(nums):
if i and not used[i - 1] and nums[i] == nums[i-1]:
continue
if not used[i]:
used[i] = True
p.append(nums[i])
self._permuteUnique(nums.copy(), used, p, result)
p.pop()
used[i] = False
def permuteUnique(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
nums.sort()
result, used = list(), list()
for _ in enumerate(nums):
used.append(False)
self._permuteUnique(nums, used, list(), result)
return result
这里我们同样可以采用之前问题的第二种写法。
class Solution:
def permuteUnique(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
if len(nums) <= 1:
return [nums]
result = []
perms = self.permuteUnique(nums[1:])
for perm in perms:
for i in range(len(perm)+1):
p = perm[:i] + [nums[0]] + perm[i:]
result.append(p)
if i < len(perm) and perm[i] == nums[0]:
break
return result
我们也可以参照之前问题中的第二种方法的思想,写出如下代码。
class Solution:
def _permuteUnique(self, nums, i, result):
if i == len(nums) - 1:
result.append(nums.copy())
return
for k in range(i, len(nums)):
if i != k and nums[i] == nums[k]: # remove duplicate num
continue
nums[i], nums[k] = nums[k], nums[i]
self._permuteUnique(nums.copy(), i + 1, result)
def permuteUnique(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
nums.sort() # remove duplicate num
result = list()
self._permuteUnique(nums, 0, result)
return result
这里我们要注意的问题是参数传递是通过赋值实现的,而python
中list
的传递是通过引用,所以我们要使用copy
这个函数。还有一点和之前的问题不同,我们没有再次swap
(第二次)。这是为什么?举个例子,[1,2*,2]
- 第一步,我们得到
[1,2*,2]
- 第二步,交换
1
和2*
,我们得到[2*,1,2]
- 第三步,交换
2
和1
,我们得到[2*,2,1]
- 接着回到第二步,此时交换
1
和2
变成[2,2*,1]
,我们发现此时的结果就和我们前面的第三步的结果重复了。
所以我们这里就不需要回溯了。
同样的,对于递归可以解决的问题,我们都应该思考是不是可以通过迭代解决,我们任然可以使用之前的方法。
class Solution:
def permuteUnique(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
if len(nums) <= 1:
return [nums]
result, index = [[]], 0
for num in nums:
tmp = []
for perm in result:
for i in range(index+1):
tmp.append(perm[:i]+[num]+perm[i:])
if i < index and perm[i] == num:
break
result = tmp
index += 1
return result
总的来说,这个问题只是在之前问题的基础上添加了一些边界条件。
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!