题目:

image.png


个人解答:

未做出,原因在于不会求子集,回溯算法需要看。
以下为回溯算法解答:

  1. class Solution {
  2. private:
  3. vector<vector<int>> result;
  4. vector<int> path;
  5. void backtracking(vector<int>& nums, int startIndex, vector<bool>& used) {
  6. result.push_back(path);
  7. for (int i = startIndex; i < nums.size(); i++) {
  8. // used[i - 1] == true,说明同一树支candidates[i - 1]使用过
  9. // used[i - 1] == false,说明同一树层candidates[i - 1]使用过
  10. // 而我们要对同一树层使用过的元素进行跳过
  11. if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
  12. continue;
  13. }
  14. path.push_back(nums[i]);
  15. used[i] = true;
  16. backtracking(nums, i + 1, used);
  17. used[i] = false;
  18. path.pop_back();
  19. }
  20. }
  21. public:
  22. vector<vector<int>> subsetsWithDup(vector<int>& nums) {
  23. result.clear();
  24. path.clear();
  25. vector<bool> used(nums.size(), false);
  26. sort(nums.begin(), nums.end()); // 去重需要排序
  27. backtracking(nums, 0, used);
  28. return result;
  29. }
  30. };

官方解答:

方法一:迭代法实现子集枚举

思路:

考虑数组 [1,2,2][1,2,2],选择前两个数,或者第一、三个数,都会得到相同的子集。

也就是说,对于当前选择的数 xx,若前面有与其相同的数 yy,且没有选择 yy,此时包含 xx 的子集,必然会出现在包含 yy 的所有子集中。

我们可以通过判断这种情况,来避免生成重复的子集。代码实现时,可以先将数组排序;迭代时,若发现没有选择上一个数,且当前数字与上一个数相同,则可以跳过当前生成的子集。

代码:

class Solution {
public:
    vector<int> t;
    vector<vector<int>> ans;

    vector<vector<int>> subsetsWithDup(vector<int> &nums) {
        sort(nums.begin(), nums.end());
        int n = nums.size();
        for (int mask = 0; mask < (1 << n); ++mask) {
            t.clear();
            bool flag = true;
            for (int i = 0; i < n; ++i) {
                if (mask & (1 << i)) {
                    if (i > 0 && (mask >> (i - 1) & 1) == 0 && nums[i] == nums[i - 1]) {
                        flag = false;
                        break;
                    }
                    t.push_back(nums[i]);
                }
            }
            if (flag) {
                ans.push_back(t);
            }
        }
        return ans;
    }
};

image.png


法二:递归法实现子集枚举

思路:

与方法一类似,在递归时,若发现没有选择上一个数,且当前数字与上一个数相同,则可以跳过当前生成的子集。

代码:

class Solution {
public:
    vector<int> t;
    vector<vector<int>> ans;

    void dfs(bool choosePre, int cur, vector<int> &nums) {
        if (cur == nums.size()) {
            ans.push_back(t);
            return;
        }
        dfs(false, cur + 1, nums);
        if (!choosePre && cur > 0 && nums[cur - 1] == nums[cur]) {
            return;
        }
        t.push_back(nums[cur]);
        dfs(true, cur + 1, nums);
        t.pop_back();
    }

    vector<vector<int>> subsetsWithDup(vector<int> &nums) {
        sort(nums.begin(), nums.end());
        dfs(false, 0, nums);
        return ans;
    }
};

image.png