https://leetcode.com/problems/permutations-ii/description/
给定一个可包含重复数字的序列,返回所有不重复的全排列。
思路:回溯。因为有重复数字,所以不能简单用in
运算符去重,改用一个不耳数组used,used[i]=True表示该位置已经用过。
回溯之前还应该排序,便于排除重复结果。
此外还需设置一个特殊条件来排除重复结果:used[i] or i-1 >= 0 and nums[i-1] == nums[i] and not used[i-1]
used[i]
表示i如果使用了,跳过,很好理解
i-1 >= 0 and nums[i-1] == nums[i] and not used[i-1]
表示看前一位,若与当前相等,且前一位未使用过,则跳过。例如对nums=[1,1,1,2],三个1是重复元素,取的时候应该作为一个整体取,即nums的0,1,2号,否则会出现重复结果。上面条件的限制使得nums[1]只有在nums[0]出现的时候才取,同理nums[2]只有在nums[1]出现的时候才取,因此保证了结果中三个1的取用先后次序为nums的0,1,2号。
注意,not used[i-1]
也可以改成used[i-1]
,即前一位使用过,则跳过。还是上面的例子,nums[0]出现后,nums[1]取不了,nums[1]出现后,nums[2]取不了,因此三个1的情况只有是先取nums的2号,然后是1号和0号,和上面反过来
两种思路都可行,都是为了保证相同元素的有序性,从而避免重复
class Solution:
def permuteUnique(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
res = []
tmpList = []
used = [False] * len(nums)
nums.sort() #重要,先排序
self.backtrack(nums, res, tmpList, used)
return res
def backtrack(self, nums, res, tmpList, used):
if len(tmpList) == len(nums):
res.append(list(tmpList))
else:
for i in range(len(nums)):
if used[i] or i-1 >= 0 and nums[i-1] == nums[i] and not used[i-1]: #注意复杂条件,最后一个可改为used[i-1]
continue
used[i] = True
tmpList.append(nums[i])
self.backtrack(nums, res, tmpList, used)
used[i] = False #记得“还原现场”
tmpList.pop()