力扣 #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;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值