子集

两种方法:回溯法 和 位运算法

1.回溯法

nums=[1 2 3]

它的子集的组成就是:要么有1,要么没有1;要么有2,要么没2;要么有3,要么没有3

所以从1开始,分成了两条支线:有1,没有1,然后有1的情况,又继续分为有2和没有2……

可以用递归来解决

class Solution {
public:
    
    //回溯
    void subset(int i,vector<int>& nums, vector<int>& tmp, vector<vector<int>>& res)
    {
            if(i>=nums.size())
                return;
            
            tmp.push_back(nums[i]);
            res.push_back(tmp);
            subset(i+1,nums,tmp,res);
            tmp.pop_back();
            subset(i+1,nums,tmp,res);
    }
    
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> res;
        
        if(nums.size()==0)
            return res;
        vector<int> tmp;
        res.push_back(tmp);//空子集
        subset(0,nums,tmp,res);
        return res;
    }
    
    
};


方法2:位运算法

nums = [1,2,3],子集有2^3=8个

用1来表示子集有nums中的某个数,0表示没有这个数。第1个数 就表示成100,第2个数 就表示成010,第3个数就表示成 001……

nums的子集有:

[] ,空集,就相当于是 000,然后与第一个数 运算 000&100 = 0,就说明没有第一个数,后面类似

再比如子集 【1,3】就写成101,与第一个数按位与,101&100 = 1,所以这个子集有nums的第一个数,与nums的第二个数按位与 101&010 = 0,所以这个子集就没有nums的第2个数

所以可以遍历nums的子集,从0——2^n-1,然后每个子集依次与nums的每个数按位与,判断这个子集有没有这个数,有的话就push_back

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        //方法2,位运算法
        vector<vector<int>>res;
        if(nums.size() == 0)
            return res;
        
        
        int all_subsets = 1<<nums.size();//一共有2^n个子集
        for(int i =0;i<all_subsets;++i)
        {
            vector<int>tmp;
            for(int j = 0;j<nums.size();++j)
            {
                if(i & (1<<j) )//如果nums中的第j个数在i所表示的子集中
                {
                    tmp.push_back(nums[j]);
                }
            }
            res.push_back(tmp);
        }
        return res;
    }
};


猜你喜欢

转载自blog.csdn.net/qq_22080999/article/details/80513368