Leetcode每日一题 90.子集 II

90. 子集 II

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

示例 1:

1
2
输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]

示例 2:

1
2
输入:nums = [0]
输出:[[],[0]]

提示:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10

本题用回溯算法比较容易理解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
public:
vector<vector<int>> res;
vector<int> sub;
int size;
public:
void back(vector<int>& nums,int start)
{
res.push_back(sub);
for(int i = start ; i < size ; i++)
{
if(i > start && nums[i] == nums[i-1])
continue;
sub.push_back(nums[i]);
back(nums,i+1);
sub.pop_back();
}
}
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
res.clear();
sub.clear();
this->size = nums.size();
sort(nums.begin(),nums.end());
back(nums,0);

return res;
}
};

首先将nums排序,因为这样才能达到去重的目的,后面说。
start是每次组合的首地址,直接看循环,分析if为什么这样写


设置i>start是为了防止第一次循环就判断nums[i] == nums[i-1],这不是我们要判断的范围,因为i==start时,明显我们只有一个元素进来。
nums[i] == nums[i-1] 是为了去重,有点不好解释,我们就这样想象,举个例子[1,2,3,3],start是0的时候我们从1进入,然后递归进入back(),不管它子递归的循环,我们就只看第一次递归的循环,是不是会得到[1,2,3,3],你们可能会说,你不是设置了nums[i] == nums[i-1]就continue吗,为什么会得到[1,2,3,3],这就是因为前面有个i>start,但如果我们在子循环时,也就是此时sub里面有[1,2]时的递归层,我们遍历到第一个3,加进去sub = [1,2,3],此时i明显已经大于start,我们不会再得到第二个[1,2,3],此时这个3是第4个3.


用一个非常妙的解释方法就是,把整个结构想象成一个树,层相同是不允许的,树枝相同是允许的。

i > start && nums[i] == nums[i-1]就诠释了这种判断。