[LeetCode] 90. Subsets II 子集合之二


 

Given a collection of integers that might contain duplicates, S, return all possible subsets.

Note:

  • Elements in a subset must be in non-descending order.
  • The solution set must not contain duplicate subsets.

 

For example,
If S = [1,2,2], a solution is:

[
  [2],
  [1],
  [1,2,2],
  [2,2],
  [1,2],
  []
]

 

這道子集合之二是之前那道 Subsets 的延伸,這次輸入數組允許有重復項,其他條件都不變,只需要在之前那道題解法的基礎上稍加改動便可以做出來,我們先來看非遞歸解法,拿題目中的例子 [1 2 2] 來分析,根據之前 Subsets 里的分析可知,當處理到第一個2時,此時的子集合為 [], [1], [2], [1, 2],而這時再處理第二個2時,如果在 [] 和 [1] 后直接加2會產生重復,所以只能在上一個循環生成的后兩個子集合后面加2,發現了這一點,題目就可以做了,我們用 last 來記錄上一個處理的數字,然后判定當前的數字和上面的是否相同,若不同,則循環還是從0到當前子集的個數,若相同,則新子集個數減去之前循環時子集的個數當做起點來循環,這樣就不會產生重復了,代碼如下:

 

解法一:

class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int> &S) {
        if (S.empty()) return {};
        vector<vector<int>> res(1);
        sort(S.begin(), S.end());
        int size = 1, last = S[0];
        for (int i = 0; i < S.size(); ++i) {
            if (last != S[i]) {
                last = S[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(S[i]);
            }
        }
        return res;
    }
};

 

整個添加的順序為:

[]
[1]
[2]
[1 2]
[2 2]
[1 2 2]

 

對於遞歸的解法,根據之前 Subsets 里的構建樹的方法,在處理到第二個2時,由於前面已經處理了一次2,這次我們只在添加過2的 [2] 和 [1 2] 后面添加2,其他的都不添加,那么這樣構成的二叉樹如下圖所示:

 

                        []        
                   /          \        
                  /            \     
                 /              \
              [1]                []
           /       \           /    \
          /         \         /      \        
       [1 2]       [1]       [2]     []
      /     \     /   \     /   \    / \
  [1 2 2] [1 2]  X   [1]  [2 2] [2] X  []

 

代碼只需在原有的基礎上增加一句話,while (S[i] == S[i + 1]) ++i; 這句話的作用是跳過樹中為X的葉節點,因為它們是重復的子集,應被拋棄。代碼如下:

 

解法二:

class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int> &S) {
        if (S.empty()) return {};
        vector<vector<int>> res;
        vector<int> out;
        sort(S.begin(), S.end());
        getSubsets(S, 0, out, res);
        return res;
    }
    void getSubsets(vector<int> &S, int pos, vector<int> &out, vector<vector<int>> &res) {
        res.push_back(out);
        for (int i = pos; i < S.size(); ++i) {
            out.push_back(S[i]);
            getSubsets(S, i + 1, out, res);
            out.pop_back();
            while (i + 1 < S.size() && S[i] == S[i + 1]) ++i;
        }
    }
};

 

整個添加的順序為:

[]
[1]
[1 2]
[1 2 2]
[2]
[2 2]

 

類似題目:

Subsets

 

參考資料:

https://leetcode.com/problems/subsets-ii/

https://leetcode.com/problems/subsets-ii/discuss/30137/Simple-iterative-solution

https://leetcode.com/problems/subsets-ii/discuss/30168/C%2B%2B-solution-and-explanation

https://leetcode.com/problems/subsets-ii/discuss/30164/Accepted-10ms-c%2B%2B-solution-use-backtracking-only-10-lines-easy-understand.

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM