diff --git a/solutions/90. Subsets II.md b/solutions/90. Subsets II.md new file mode 100644 index 0000000..a3056de --- /dev/null +++ b/solutions/90. Subsets II.md @@ -0,0 +1,112 @@ +# [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>&res, vector&subset, vector&visited, const vector& 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> subsetsWithDup(vector& nums) { + vector>res; + vectorsubset; + vectorvisited(nums.size(), false); + sort(nums.begin(), nums.end()); + DFS(res, subset, visited, nums, 0); + return res; + } +}; +``` +### 简洁版 +``` C++ +class Solution { +void DFS(vector> &res, int level, vector &subset, vector &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> subsetsWithDup(vector& nums) { + vector>res; + vectorsubset; + vectorvisited(nums.size(), false); + sort(nums.begin(), nums.end()); + DFS(res, 0, subset, nums); + return res; + } +}; +``` +## 思路二 +``` C++ +class Solution { +public: + vector> subsetsWithDup(vector &nums) { + vector>res; + res.push_back(vector{}); + 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; + } +}; +```