力扣 #78 子集(C++)

题目如下:原题链接

题目

法一 依次考虑每个元素

  利用递归,依次考虑每个元素的取舍,这样一共能得到2n个状态,递归深度最深为n层。这里有一个小优化,定义一个全局的vector<int> 用来存放递归取的元素集合,每当取一个元素,则push_back,当递归回溯的时候就pop_back,这样递归的时候就无需传入额外的vector<int>数组了。

class Solution {
    
    
public:
    vector<vector<int>> ans;
    vector<int> tmp;
    vector<vector<int>> subsets(vector<int>& nums) {
    
    
    	//从第0层开始递归
        dfs(0,nums);
        return ans;
    }
	//传入nums的引用,加快了递归的过程,同时减小空间开销
    void dfs(int n,vector<int> &nums){
    
    
    	//递归达到边界
        if(n==nums.size()){
    
    
            ans.push_back(tmp);
            return;
        }
        //不取这个元素
        dfs(n+1,nums);
        //取这个元素
        tmp.push_back(nums[n]);
        dfs(n+1,nums);
        //递归回溯,将这个元素从集合中删去
        tmp.pop_back();
    }
};

法二 位运算求解

  假设我们从 [1,2]中生成子集,那么可以有四个子集,分别是空集(0b00)、{2}(0b01),{1}(0b10),{1,2}(0b11),注意到原数组只有两个元素,上述的四个子集可以看成是 0 - 3 的二进制这四种状态,对应位的1代表取那个数,而0代表不取那个数,此时一共可以得到2n个子集,符合我们的认知。可以利用此性质来进行求解,这样可以使用递推来求解而非递归。

class Solution {
    
    
public:
    vector<vector<int>> subsets(vector<int>& nums) {
    
    
    	//n为2^(nums元素个数) 
        int n=1<<(nums.size());
        vector<vector<int>> ans;
		//每个i对应一种状态
        for(int i=0;i<n;i++){
    
    
            vector<int> tmp;
            //针对每一位来判断是否取该位数字
            for(int j=0;j<nums.size();j++)
            	//为1,则取该数字
                if(i&(1<<j))
                    tmp.push_back(nums[j]);
            //将这种状态加入ans
            ans.push_back(tmp);
        }
        return ans;
    }
};

猜你喜欢

转载自blog.csdn.net/Raymond_YP/article/details/108699980