第67题 Subsets

本文介绍使用C++实现从给定整数数组生成所有可能子集的方法。采用深度优先搜索(DFS)递归策略,详细阐述了三种不同的实现方式,并解释了背后的逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Given a set of distinct integers, nums, return all possible subsets.

Note:

  • Elements in a subset must be in non-descending order.
  • The solution set must not contain duplicate subsets.

For example,
If nums = [1,2,3], a solution is:

[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]

Hide Tags
  Array Backtracking Bit Manipulation



















Solution in C++1:
class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> result;
        if(nums.size()==0) return result;
        sort(nums.begin(), nums.end());
        vector<int> levelResult;
        getSubsets(nums, 0, levelResult, result);
        
        return result;
    }
    
    void getSubsets(vector<int>& nums, int height, vector<int> curResult, vector<vector<int>>& result){
        if(height==nums.size()){
            result.push_back(curResult);
            return;
        }else{
            getSubsets(nums, height+1, curResult, result);
            curResult.push_back(nums[height]);
            getSubsets(nums, height+1, curResult, result);
        }
    }
};

Note:
基于深度优先遍历的递归。根据nums数组构建一棵树,根到叶子的路径代表nums[0]到nums[len-1]的状态。左分支表示该数字加入集合,右分支表示该数字不加入集合。每个叶子结点为一个结果,所有叶子结点的集合猥琐求结果。所以用DFS递归思想求得所有叶子结点。

Solution in C++ 2:
class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> result;
        if(nums.size()==0) return result;
        sort(nums.begin(), nums.end());
        for(int i=0; i<nums.size(); i++){
            getSubsets(nums, i, result);
        }
        vector<int> emp;
        result.push_back(emp);
        return result;
        
    }
    
    void getSubsets(vector<int>& nums, int index, vector<vector<int>>& result){
        int curSize = result.size();
        for(int i=0; i<curSize; i++){
            vector<int> cur = result[i];
            result[i].push_back(nums[index]);
            result.push_back(cur);
        }
        vector<int> single;
        single.push_back(nums[index]);
        result.push_back(single);
        
    }
};
Note: 
只要我们能找到比原问题规模小却同质的问题,都可以用递归解决。比如要求{1, 2, 3}的所有子集,可以先求{2, 3}的所有子集,{2, 3}的子集同时也是{1, 2, 3} 的子集,然后我们把{2, 3}的所有子集都加上元素1后(注意排序),又得到同样数量的子集, 它们也是{1, 2, 3}的子集。这样一来,我们就可以通过求{2, 3}的所有子集来求 {1, 2, 3}的所有子集了。即为求1,2,3的子集,要先求2,3的子集,然后再把1加入到2,3的子集中去,典型的递归思路。代码如下:
reference from http://www.tuicool.com/articles/J3En2e
其实就是每次有一个新数,就把它加到已经存在的所有子集的后面。记得每次在循环里把只包含这个数本身的子集添加进去。而且每次在已存在的子集后面添加新数形成新子集时,别忘了要把修改前的子集重新添加到result里,因为之前的子集必然也是一个合法的subset。还有记得最后在结果里添加上空子集。
Solution in C++ 3:
class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> result;
        if(nums.size()==0) return result;
        sort(nums.begin(), nums.end());
<span style="white-space:pre">	//n个数有0~max-1即2^n中组合,1<<n表示2^n</span>
        int max = 1<<nums.size();
        for(int i=0; i<max; i++){
            vector<int> cur;
            int index = 0, bound = i;
            while(bound>0){
                if(bound&1)
                    cur.push_back(nums[index]);
                bound>>=1;
                index++;
            }
            result.push_back(cur);
        }
        return result;
        
    }
    
};
Note:
求子集问题就是求组合问题。数组中的n个数可以用n个二进制位表示,当某一位为1表示选择对应的数,为0表示不选择对应的数。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值