往期博客:
目录
题目
给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
题目分析:
已知:整数数组(包含重复元素)
目的:返回所有子集
要求:子集不能重复
示例
示例1
输入:nums = [1,2,2] 输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]
示例2
输入:nums = [0] 输出:[[],[0]]
解析
这道题其实和LeetCode78-子集基本相同,相当于是其扩展,两道题的主要不同就是本题所给的整数数组中有重复元素,而78题所给的整数数组中不包含重复元素,包含重复元素就意味着组成的子集中相同的子集就比较多,所以要考虑是否为重复的子集就比较复杂。
既然本题相比78题的重复子集比较多,那么我们可以进一步设置去重条件进行去重处理,去充原则是如果当前组成的子集已经在结果集中(在结果集中意味着前面已经组成了该子集)则当前子集不再加入结果集,例如对于整数数组[1,2,2],第一个元素1和第二个元素2组成子集[1,2]并加入结果集,而第一个元素1和第三个元素2同样组成子集[1,2],但两个子集相同,结果集中已经有一个[1,2]了,所以此时的[1,2]就不再加入结果集中。
但是,对于整数数组[2,1,2]有出现了新问题,对于子集[1,2]和子集[2,1],两个子集是不相同的,但是对于本题来说两个子集为重复子集,所以单纯的考虑通过判断两个子集是否相同来去重不行
我们可以先对整数数组进行sort排序,排序后[2,1,2]变成[1,2,2],此时去重原则仍成立。
所以综上分析可知,本题只需要在78题代码的基础上添加排序和去重两个步骤即可
详细解析请看:LeetCode78-子集
代码
扩展法
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
result = [[]]
# 排序
nums.sort()
for num in nums:
result += [i+[num] for i in result if i+[num] not in result] # 去重
return result
回溯法
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
result = []
# 排序
nums.sort()
for i in range(len(nums)+1):
self.backtracking(nums, i, 0, [], result)
return result
def backtracking(self, sorted_nums: List[int], length: int, index: int, cur, res):
if len(cur) == length:
res.append(cur[:])
return
for i in range(index, len(sorted_nums)):
if i > index and sorted_nums[i] == sorted_nums[i-1]: # 去重
continue
cur.append(sorted_nums[i])
self.backtracking(sorted_nums, length, i+1, cur, res)
cur.pop()
深度优先搜索
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
result = []
# 排序
nums.sort()
self.dfs(nums, [], result)
return result
def dfs(self, sorted_nums, cur, result):
result.append(cur)
for i in range(len(sorted_nums)):
if i > 0 and sorted_nums[i] == sorted_nums[i-1]:
continue
else:
self.dfs(sorted_nums[i+1:], cur+[sorted_nums[i]], result)