(nice)LeetCode 90. 子集 II (位运算 || dfs)

90. 子集 II

在这里插入图片描述
思路:有三种方法解决本题
方法一:我们用位运算,这里数组个数最多为10,那么我们就用第一层循环把0~2^lens - 1都遍历一遍i,再用第二层循环来遍历对应的数i二进制下哪些位置为1,为1就代表选中。然后用集合来确保不会有重复的。时间复杂度0(2^n)

class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        vector<vector<int>> v;
        set<vector<int>> st;
        //下面这个sort,和后面的sort选一个用就可以。
        //原因就是因为排好序后,就不用怕集合里的元素因为“数组里元素位置不同(包含的数都一样,但位置不一样)”而不同
        //sort(nums.begin(),nums.end());
        int lens=nums.size();
        for(int i=0;i<(1<<lens);i++){
            vector<int > tmp;
            for(int j=0;j<lens;j++){
                if(i>>j&1){
                    tmp.push_back(nums[j]);
                }
            }
            sort(tmp.begin(),tmp.end());
            if(st.find(tmp)==st.end()){
                st.insert(tmp);
                v.push_back(tmp);
            }
        }
        return v;
    }
};

方法二:用dfs再加上一个集合来去重

class Solution {
public:
    vector<vector<int>> v;
    vector<int> tmp;
    set<vector<int>> st;
    void dfs(vector<int>& nums,int u){
        if(u==nums.size()){
            if(st.find(tmp)==st.end()){
                v.push_back(tmp);
                st.insert(tmp);
            }
            return ;
        }
        tmp.push_back(nums[u]);
        dfs(nums,u+1);
        tmp.pop_back();
        dfs(nums,u+1);
    }
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        dfs(nums,0);
        return v;
    }
};

方法三:速度最快,避免了重复元素的大量遍历操作,而且还节省空间。在dfs里通过一层for循环来将深度变成宽度。具体细节看注释

class Solution {
public:
    vector<vector<int>> v;
    vector<int> tmp;
    void dfs(vector<int>& nums,int u){
        if(u==nums.size()){
            v.push_back(tmp);
            return ;
        }
        for(int i=u;i<nums.size();i++){
            if(i==u||(i!=u&&nums[i-1]!=nums[i])){ 
            //在这里排除的是对重复元素的二次dfs
            //重复元素的第一次dfs里的选,然后再下一层dfs里的不选,其实就已经重复了第二次dfs
                tmp.push_back(nums[i]);
                dfs(nums,i+1);
                tmp.pop_back();
            }
            //在这里加上这个就是因为题目要的是所有可能的子集
            //不加上会漏掉u~nums.size()-1里均不选的情况
            if(i==nums.size()-1){
                v.push_back(tmp);
                return ;
            }
        }
    }
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(),nums.end());//先排序,好在dfs里对重复的元素进行操作
        dfs(nums,0);
        return v;
    }
};

思考:方法一和方法二相对于方法三来说,想到的速度会更快,但运行时间而言,方法三无疑是最快的,他避免了重复元素的大量遍历操作,而且还节省空间。我的这篇博客LeetCode 《组合总和》系列题目总结(很nice!!!),有用到dfs里加一层for循环的方法。可以学习加深思考。

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值