题目描述
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
思路
本题在leetcode-46.全排列的基础上加上了去除重复排列的限制,大体思路一样,只是在构建排列树时,我们需要进行减枝。一个比较容易想到的办法是在结果集中去重。但是问题来了,这些结果集的元素是一个又一个列表,对列表去重不像用哈希表对基本元素去重那样容易。如果要比较两个列表是否一样,一个容易想到的办法是对列表分别排序,然后逐个比对。既然要排序,我们就可以 在搜索之前就对候选数组排序,一旦发现某个分支搜索下去可能搜索到重复的元素就停止搜索,这样结果集中不会包含重复列表。为了更直观地理解,以测试用例[1,1,2]为例,见下图
虚线框出的就是重复的排列,那么如何在搜索的时候进行排除呢?
可以发现,当搜索到红色的1时,是刚从它的左兄弟,即黑色的1回溯出来,这样的情况,有两个特点:
1.当前搜索的节点和上一次搜索的节点数值上相等
2.上一次搜索的节点没在使用(回溯后used会置False)
比如:对于[2,
1
\color{#FF0000}{1}
1],当前搜索到
1
\color{#FF0000}{1}
1,它是由1回溯后搜索得到,他们的值相等,且因为回溯,1的used置为False,那么根据规律,[2,
1
\color{#FF0000}{1}
1]需要被减枝。
代码实现(py3)
"""
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
"""
def dfs(nums, depth, path, used, res):
# 已经到了叶子节点
if(depth == len(nums)):
res.append(path.copy())
return
for i in range(len(nums)):
if used[i] or (i > 0 and used[i - 1] == False and nums[i] == nums[i - 1]):
continue
# 还没被选过
path.append(nums[i])
used[i] = True
dfs(nums, depth + 1, path, used, res)
# 回溯
path.pop()
used[i] = False
class Solution:
def permuteUnique(self, nums):
path = []
used = []
depth = 0
res = []
for _ in range(len(nums)):
used.append(False)
if len(nums) == 0:
return res
nums.sort()
dfs(nums, depth, path, used, res)
return res