LeetCode/solutions/90. Subsets II.md
2019-03-22 16:38:00 +08:00

113 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# [90. Subsets II](https://leetcode.com/problems/subsets-ii/)
# 思路
这题就是[78. Subsets](https://leetcode.com/problems/subsets/)的升级版,做法也和此题类似,可参考之前[78. Subsets题解](https://github.com/ShusenTang/LeetCode/blob/master/solutions/78.%20Subsets.md)。
为了使相同的元素都是挨着的我们首先需要对nums进行排序。
## 思路一、DFS
构造一棵二叉树,左子树表示选择该层处理的节点,右子树表示不选择,最终的叶节点就是所有子集合,以[1,2,2]为例,树的结构如下:
```
[]
/ \
/ \
/ \
[1] []
/ \ / \
/ \ / \
[1 2] [1] [2] []
/ \ / \ / \ / \
[1 2 2] [1 2] X [1] [2 2] [2] X []
```
需要注意去掉重复值,即对树进行剪枝: 当前一层的元素(`nums[level-1]`)未被访问且`nums[level]==nums[level-1]`时,当前元素`nums[level]`也不应该访问,即只沿右子树下降。
## 思路二
此题也可以使用迭代的方式来完成此题。
参考[78. Subsets题解](https://github.com/ShusenTang/LeetCode/blob/master/solutions/78.%20Subsets.md)当处理到第一个2时此时的子集合为[], [1], [2], [1, 2]
而这时再处理第二个2时如果在[]和[1]后直接加2会产生重复所以只能在上一个循环生成的后两个子集合后面加2。
所以我们用last来记录上一个处理的数字然后判定当前的数字和上面的是否相同若不同则循环还是从0到当前子集的个数若相同
则新子集个数减去之前循环时子集的个数当做起点来循环,这样就不会产生重复了。
# C++
## 思路一
### 好理解版
``` C++
class Solution {
private:
void DFS(vector<vector<int>>&res, vector<int>&subset, vector<bool>&visited, const vector<int>& nums, int level){
if(level == nums.size()) { // 叶节点
res.push_back(subset);
return;
}
if(level > 0 && nums[level] == nums[level - 1] && !visited[level - 1]){
DFS(res, subset, visited, nums, level + 1); // 沿右子树下降
return;
}
// 沿左子树下降
visited[level] = true;
subset.push_back(nums[level]);
DFS(res, subset, visited, nums, level + 1);
visited[level] = false;
subset.pop_back();
// 沿右子树下降
DFS(res, subset, visited, nums, level + 1);
}
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
vector<vector<int>>res;
vector<int>subset;
vector<bool>visited(nums.size(), false);
sort(nums.begin(), nums.end());
DFS(res, subset, visited, nums, 0);
return res;
}
};
```
### 简洁版
``` C++
class Solution {
void DFS(vector<vector<int>> &res, int level, vector<int> &subset, vector<int> &nums) {
res.push_back(subset);
for (int i = level; i < nums.size(); ++i) {
subset.push_back(nums[i]);
DFS(res, i + 1, subset, nums);
subset.pop_back();
while (i + 1 < nums.size() && nums[i] == nums[i + 1]) ++i;
}
}
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
vector<vector<int>>res;
vector<int>subset;
vector<bool>visited(nums.size(), false);
sort(nums.begin(), nums.end());
DFS(res, 0, subset, nums);
return res;
}
};
```
## 思路二
``` C++
class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int> &nums) {
vector<vector<int>>res;
res.push_back(vector<int>{});
sort(nums.begin(), nums.end());
int last = nums[0], size = 1;
for(int i = 0; i < nums.size(); i++){
if(last != nums[i]){
last = nums[i];
size = res.size();
}
int newSize = res.size();
for (int j = newSize - size; j < newSize; ++j) {
res.push_back(res[j]);
res.back().push_back(nums[i]);
}
}
return res;
}
};
```