#Leetcode-78. 子集

子集:

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。

示例:

输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]

思路1:
刚开始写的时候想着按照子集中元素个数枚举,这样就可以沿用77.组合的思路求解。

代码如下:

class Solution {
public:
    vector<vector<int>> res;
    void dfs(int index, int n, int k, vector<int>& temp, vector<int>& nums){
        if(k == 0){
            res.push_back(temp);
            return;
        }
        for(int i = index; i < n - k + 1; i++){
            temp.push_back(nums[i]);
            dfs(i + 1, n, k-1, temp, nums);
            temp.pop_back();
        }
    }
    vector<vector<int>> subsets(vector<int>& nums) {
        res.clear();
        res.push_back({});
        int n = nums.size();
        if(n == 0) return res;
        res.push_back(nums);
        for(int i = 1; i < n; i++){ //按子集中元素个数顺序计算
            vector<int> temp;
            dfs(0, n, i, temp, nums); //计算所有含有i个元素的组合
        }
        return res;
    }
};

很明显这个算法把题目做复杂了,回溯的复杂度为O(i * C(n,i)),i又从1到n求和;

思路2:
换个思路,其实这就是一个数学题,对每一个元素无非是选与不选两个操作,用二进制表示就是0011这样的一串数,于是所有情况就是从00…00 到 11…11

代码如下:

class Solution{
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> res;
        for(int i = 0; i < (1<<nums.size()); i++){ //位运算
            vector<int> temp;
            for(int j = 0; j < nums.size(); j++){
                if(((i>>j) & 1) == 1) temp.push_back(nums[j]);
            }
            res.push_back(temp);
        }
        return res;
    }
};

思路3:
其实一个数选与不选还可以这样想,如果选就代表多了:在已存储的子集中加入这一元素而产生的新集合。
注:空集合是初始情况

代码如下:

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> res;
        res.push_back({});
        int n = nums.size();
        for(auto c:nums){
            int size = res.size();
            for(int i = 0; i < size; i++){
                vector<int> temp = res[i];
                temp.push_back(c);
                res.push_back(temp);
            }
        }
        return res;
    }
};

思路4:
另外还看到一种用二叉树形象表示所有情况的解法:点击链接查看
思路就是用左子树表示不选,右子树表示选,等到达树底部的时候就得到了一个子集
来自dao-fa-zi-ran-2
代码如下:

class Solution{
public:
    void preOrder(vector<int>& nums, int i, vector<int> subset, vector<vector<int>>& res) {
        if(i == nums.size()){ //到达树底时记录
            res.push_back(subset);
            return;
        }
        subset.push_back(nums[i]); //这里用左子树代表选第i个数
        preOrder(nums, i + 1, subset, res);
        subset.pop_back();
        preOrder(nums, i + 1, subset, res);
    }
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> res;
        vector<int> temp;
        preOrder(nums, 0, temp, res);
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值