LeetCode78. 子集

方法一(DFS回溯)

求出所有可能的子集,就是要遍历一遍DFS递归树,把所有子集全都压入结果数组中。

class Solution {
vector<vector<int>> res;
vector<int> onePath;                  //onePath是递归树的一条路径(一个子集)
public:      
    vector<vector<int>> subsets(vector<int>& nums) {
        DFS(nums, 0);
        return res;
    }
    void DFS(vector<int>& nums, int depth) {            //depth是当前递归的深度
        res.push_back(onePath);                         //要求所有子集,所以把onePath压入res先
        for(int i = depth; i < nums.size(); ++i) {      //继续往深处搜索
            onePath.push_back(nums[i]);
            DFS(nums, i + 1);                          
            onePath.pop_back();                        //DFS回溯都是对称的,所以要恢复现场
        }
    }
};

方法二(二进制位运算)

对于长度为n的数组,我们可以枚举所有长度为n的二进制串,并与数组元素进行与运算,
二进制串中的0表示子集不选这个数,1表示子集选这个数,
这样就直接枚举了所有的子集。

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> res;
        for(int i = 0; i < 1 << nums.size(); ++i) {            //枚举i从 0 ~ 2的nums.size()-1次方减一
            vector<int> oneSubset;
            for(int j = 0; j < nums.size(); ++j) {              //二进制串的长度是nums.size(),所以我们要逐位看看当前二进制串的各个位是0还是1(表示选还是不选)
                if((i >> j) & 1) {                              //判断i的二进制第j位是否为1,要把i右移j位与1做与运算
                    oneSubset.push_back(nums[j]);               //如果是1,说明选第j个数,子集加上nums[j]
                }
            }
            res.push_back(oneSubset);                        //甭管现在子集是啥,肯定是原来没有的(每个二进制子串都不同),所以把子集加入res数组,安排!
        }
        return res;
    }
};
原文地址:https://www.cnblogs.com/linrj/p/13237356.html