• 90 子集II


    题目

    给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

    解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

    示例 1:

    输入:nums = [1,2,2]
    输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]
    示例 2:

    输入:nums = [0]
    输出:[[],[0]]

    • 法一:递归
    class Solution {
    public:
        vector<vector<int>> subsetsWithDup(vector<int>& nums) {
            vector<vector<int>> result;
            vector<int> subset;
            sort(nums.begin(),nums.end());//排序,如果相邻两个数相同就跳过,去重
            dfs(subset,0,result,nums);
            return result;
        }
    
        void dfs(vector<int> &subset, int cur,vector<vector<int>> &result, vector<int> &nums)
        {
            if(cur==nums.size())//判断到最后一个数字后将子集加入result
            {
                result.push_back(subset);
                return;
            }
    		//一定要先选择该元素再不选该元素,顺序不可颠倒。选择该元素时相同数字可以多次选择,不需要去重。去重只有在数字相同且前一个元素没有选时才需要判断
    		//选择该元素,直接递归选下一个元素
            subset.push_back(nums[cur]);
            dfs(subset,cur+1,result,nums);
            subset.pop_back();//恢复现场
    		//不选该元素,去重,将与该数字相同的元素全部跳过,最终cur指向与该数字不同的第一个元素
    		//因为选该数字的情况已经有了,如上;不选该数字的情况也右了。下一次递归就只能是不同的数字,所以去重方法如下
            while(cur<nums.size()-1&& nums[cur]==nums[cur+1]) cur++;
            //此时只能是当前数字与后一个数字比较,时退出循环时cur指向的就是最后一个与该数字相同的数字,且用dfs时传入的是cur+1,即下一个不同数字。
            //如果是当前数字与前一个数字比较,那么要先排除第一个元素,即判断条件cur!=0。该方法cur最后指向该元素后第一个新的数字,dfs传入的就是cur,但是对于传入的是第一个元素时就会陷入死循环,永远都是选择第一个元素
            dfs(subset,cur+1,result,nums);
    
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 时间复杂度O(2^n)

    • 空间复杂度O(n)

    • 思路

      • 对每一个元素,选择要或者不要。此处的去重方法是,对数组先排序,对于每一个元素,选择要时都直接递归,选择不要时跳过所有于当前数字相同的元素,直接从数字不同的元素开始下一次递归。
      • 详细解释在代码中的注释
    • 法二:二进制法迭代

    class Solution {
    public:
        vector<vector<int>> subsetsWithDup(vector<int>& nums) {
            vector<vector<int>> result;
            int n=nums.size();
            sort(nums.begin(),nums.end());//排序方便去重
            //每一个int表示一种排列,一共有1<
            //对每一个排列,确定没有重复后就转化为子集加入结果中
            for(int i=0; i<(1<<n); i++)
            {
                bool flag=true;//去重标志
                vector<int> subset;//存放一个子集
                //将排列转化为子集
                for(int j=0; j<n; j++)
                {
                    if(i&(1<<j))//取该排列的每一位值为1时对应的数字
                    {
                    	//j!=0且nums[j]==nums[j-1]判断相邻两个元素是否相同
                    	//1<
                    	//如果当前元素的前一个元素与该元素相同,且没有被选,则该子集已经存在了,将flag置为false然后跳出循环
                        if(j!=0 && nums[j]==nums[j-1]&& (i&(1<<(j-1)))==0) 
                        {
                            flag=false;
                            break;
                        }
                        subset.push_back(nums[j]);//选择该元素                
                    }
                }
                if(flag)//没有重复则加入该结果集
                {
                    result.push_back(subset);
                }
            }
            return result;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 时间复杂度O(2^n)
    • 空间复杂度O(n)
    • 思路
      • 每一个int都表示一种排列,一共有1<
      • 对每一个排列,其中数字为1则表示该子集中有这个数字,所以只需去重后遍历该排列,将值为1对应的数字加入子集中
      • 去重:先对数组排序,然后每次判断相邻两个元素如果相同且前一个数字没选,则跳过该排列。
  • 相关阅读:
    E. Block Sequence-Codeforces Round 903 (Div. 3)
    Linux配置成代理服务器
    linux平台的无盘启动开发
    Socket网络编程(五)——TCP数据发送与接收并行
    什么是接口
    部署3节点k8s集群,要求使用版本1.24.2。
    【愚公系列】2022年07月 Go教学课程 024-函数
    JS——经典案例
    Github 2024-04-18 开源项目日报 Top10
    Apache Ranger:(一)安装部署
  • 原文地址:https://blog.csdn.net/weixin_45781228/article/details/126005573