求幂集的更新贴

求幂集

位运算

比如我们求{1, 2, 3}的幂集,左边的格子,从上到下分别是0-7.
然后0代表空集,1代表{1},…,7代表{1,2,3}
在这里插入图片描述
当然如果数组超过32位要再处理一下。因为int为32位。

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
         vector<vector<int>> res;  
         //子集的长度是2的nums.size次方,这里通过移位计算
        size_t total = 1 << nums.size();  
        for (size_t i = 0; i < total; ++i) {
            vector<int> vec;
            //num也是从0到7,一个for循环一个数
            size_t num = i, idx = 0;
            while (num) {
      //如果数字num的某一位是1,就将nums对应的那一位的数字添加到集合
                if (num & 1)
                    vec.push_back(nums[idx]);
                num >>= 1;
                ++idx;
            }
            res.push_back(vec);
        }
        return res;

    }
};

递推

输入 0 -->[[]]
输入 1 -->[[],[1]]
输入 2 -->[[],[1],[2],[1,2]]
输入 3 -->[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
可以获得 递推公式: f(n) = f(n-1) + [i+[num] for i in f(n-1)]

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        res = [[],]
        if not nums:
            return res
            
        for num in nums:
            res += [arr+[num] for arr in res]
        return res

用python写的很简短。
C++如下

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

    }
};

DFS

跟之前发过的一样,面临的永远是还是不选的问题
当然这个图和下面的例子不太恰当,但思想是一样的。
在这里插入图片描述

class Solution {
public:
   vector<int>tmp; 
   vector<vector<int>> res;
   int n;
    vector<vector<int>> subsets(vector<int>& nums) {
       n = nums.size();
       dfs(nums,0);
       return res;
    }
    void dfs(vector<int>&num,int loc){
          if(loc == n){
              res.push_back(tmp);
              return;
          }
          tmp.push_back(num[loc]);
          dfs(num,loc+1);  //要num[loc]
          tmp.pop_back();
          dfs(num,loc+1);   //不要num[loc]
    }
};

比如求{0,1,2}的幂集,res的结果是{{0,1,2},{0,1},{0,2},{0},{1,2},{1},{2},{}}.注意顺序。
前四个有0元素,后四个无0元素。就是要与不要。

回溯(暴力递归)

跟上面类似,也是不选的问题。
只不过这个用了个for循环

class Solution {
public:
    vector<vector<int>> ans;
    void dfs(vector<int>& nums, int index, vector<int>& res) {
        ans.push_back(res);
        if (index >= nums.size())
            return;
        for (int i = index; i < nums.size(); i++) {
            res.push_back(nums[i]);  //要nums[i]之后dfs
            dfs(nums, i + 1, res);
            res.pop_back();  //不要nums[i],进入下一个for循环,i++        
        }
    }
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<int> res;
        dfs(nums, 0, res);
        return ans;
    }
};

{1,2,3}的幂集应该是,
{}
第一轮for循环{1,2,3},{1,2}, {1,3},{1}
第二轮for循环{2,3},{2}
第三轮for循环{3}

总结

本篇基本都来源于leetcode点赞很高的解法
前两种方法比较取巧,位运算yyds,递推稍微有点数学功底,都是很好的方法。
后两种感觉类似于一种,就是一个不要的问题,去递归。
文章写的很垃圾,多谢各位评论区指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值