[LeetCode 90]子集 II

90. 子集 II

基本是看这位大佬的题解,用C++实现了一遍

1.回溯法

这个比较好改,我们只需要判断当前数字和上一个数字是否相同,相同的话跳过即可。当然,要把数字首先进行排序。

class Solution {
  public:
    vector> subsetsWithDup(vector &nums) {
        vector> res;
        vector item;
        sort(nums.begin(), nums.end());
        helper(res, item, nums, 0);
        return res;
    }

    void helper(vector> &res, vector item, vector &nums,
                int level) {
        res.push_back(item);
        for (int i = level; i < nums.size(); i++) {
            if (i > level && nums[i] == nums[i - 1])
                continue;
            item.push_back(nums[i]);
            helper(res, item, nums, i + 1);
            item.pop_back();
        }
    }
};

int main() {
    Solution s;
    vector nums = {1, 2, 2, 2, 3};
    vector> res;
    res = s.subsetsWithDup(nums);
    for (int i = 0; i < res.size(); i++) {
        for (int j = 0; j < res[i].size(); j++) {
            cout << res[i][j] << " ";
        }
        cout << endl;
    }

    cout << endl << res.size();

    return 0;
}

2.迭代法

我们发现出现了重复的数组,那么我们可不可以像解法一那样,遇到重复的就跳过这个数字呢?答案是否定的,如果最后一步 [ 1 2 2 ] 增加了 2 ,跳过后,最终答案会缺少 [ 2 2 ]、[ 1 2 2 ] 这两个解。我们仔细观察这两个解是怎么产生的。

[LeetCode 90]子集 II_第1张图片

我们看到第 4 行黑色的部分,重复了,是怎么造成的呢?

第 4 行新添加的 2 要加到第 3 行的所有解中,而第 3 行的一部分解是旧解,一部分是新解。可以看到,我们黑色部分是由第 3 行的旧解产生的,橙色部分是由新解产生的。

而第 1 行到第 2 行,已经在旧解中加入了 2 产生了第 2 行的橙色部分,所以这里如果再在旧解中加 2 产生黑色部分就造成了重复。

所以当有重复数字的时候,我们只考虑上一步的新解,算法中用一个指针保存每一步的新解开始的位置即可。

class Solution {
  public:
    vector> subsetsWithDup(vector &nums) {
        vector> res(1);
        sort(nums.begin(), nums.end());
        int start = 1;
        for (int i = 0; i < nums.size(); i++) {
            int len = res.size();
            for (int j = 0; j < len; j++) {
                if (i > 0 && nums[i] == nums[i - 1] && j < start)
                    continue;
                vector tmp = res[j];
                tmp.push_back(nums[i]);
                res.push_back(tmp);
            }
            start = len;
        }
        return res;
    }
};

你可能感兴趣的:([LeetCode 90]子集 II)