您的位置:首页 > 编程语言 > C语言/C++

[C++]LeetCode: 63 Subsets

2014-12-30 21:13 435 查看
题目:

Given a set of distinct integers, S, 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 S =
[1,2,3]
, a solution is:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]

Answer 1 :
DFS方法


思路解析:求集合的所有子集的问题。题目要求子集中元素非递减排列。因此,首先要对原来的集合排序。

原来的集合中的每一个元素在子集中只有两种状态:要么存在,要么不存在。这样构造子集的过程中每个元素就有两种选择方法,选择、不选择。因此可以构造一个二叉树,例如对例子中集合{1,2,3}构造的二叉树如下{左子树表示选择该层处理的元素,右子树表示不选择},最后得到的叶子结点就是要求的子集。



Attention:

1. 通过原来的集合的元素总数,判断是否到达叶子结点。

<strong>  </strong>//达到叶子结点,一个集合元素选择结束
        if(ileaf == S.size())
        {
            ret.push_back(tmpres);
            return;
        }
2. 每次对一个元素进行选择时,先push, 后pop. 下一层递归后返回到原函数此点,还是调用下一层递归前的状态(层层递归返回时依次pop掉了),所以pop的是该次push进的元素。

//选择ileaf元素
tmpres.push_back(S[ileaf]);
subsets_helper(S, tmpres, ileaf + 1, ret);
        
//不选择ileaf元素,将ileaf pop出来
tmpres.pop_back();
subsets_helper(S, tmpres, ileaf + 1, ret);


AC Code:
class Solution {
public:
    vector<vector<int> > subsets(vector<int> &S) {
        vector<vector<int>> ret;
        vector<int> tmpres;
        int len = S.size();
        if(len == 0) return ret;
        sort(S.begin(), S.end());
        subsets_helper(S, tmpres, 0, ret);
        return ret;
    }
    
    void subsets_helper(vector<int>& S, vector<int>& tmpres, int ileaf, vector<vector<int>>& ret)
    {
        //达到叶子结点,一个集合元素选择结束
        if(ileaf == S.size())
        {
            ret.push_back(tmpres);
            return;
        }
        
        //选择ileaf元素
        tmpres.push_back(S[ileaf]);
        subsets_helper(S, tmpres, ileaf + 1, ret);
        
        //不选择ileaf元素,将ileaf pop出来
        tmpres.pop_back();
        subsets_helper(S, tmpres, ileaf + 1, ret);
    }
};


Answer 2:

观察上面的二叉树,可以发现,

当前层的集合 = 上一层的集合 + 上一层的集合加入当前层处理的元素, 即为当前的所有集合(树根为空集),因此可以从第二层开始(第一层空集)迭代的求出最后一层的所有集合(即叶子结点)

Attention:

1. 从第二层开始迭代,第一层视为空集,需要先初始化。

vector<vector<int> > res(1);//开始加入一个空集
2. 由于每次添加的集合个数是由上一层决定的,下一层是上一层的两倍,所以需要处理每个元素前,计算上一层的集合个数,确定迭代次数。

int resSize = res.size();
for(int j = 0; j < resSize; j++)
3. 注意先复制上一层的集合,再在该集合的最后一个元素后添加当前元素。注意末尾添加元素的方法

for(int j = 0; j < resSize; j++)
{
     //复制一遍当前集合,并在其后添加元素S[i]
      res.push_back(res[j]);
      res.back().push_back(S[i]);
}


AC Code:

class Solution {
public:
    vector<vector<int> > subsets(vector<int> &S) {
        int len = S.size();
        //第一层先加入一个空集合
        vector<vector<int>> res(1);
        sort(S.begin(), S.end());
        
        for(int i = 0; i < len; i++)
        {
            int resSize = res.size();
            for(int j = 0; j < resSize; j++)
            {
                //复制一遍当前集合,并在其后添加元素S[i]
                res.push_back(res[j]);
                res.back().push_back(S[i]);
            }
        }
        
        return res;
    }
};


Answer 3 :
二进制思想(待研究 Bitmap)


可以根据二进制的思想,比如对于3个元素的集合,000表示一个元素都不选择,001表示选择第一个元素,101表示选择第一个和第三个元素...。因此如果集合大小为n,我们只需要让一个整数从0逐渐增加到2^n-1, 每个整数的二进制形式可以表示一个集合。如果用整数的二进制表示集合,这个算法有个限制,最大能表示集合元素的个数为64(unsigned
long long)。如果使用bitmap,然后模拟二进制的加1操作,则对集合大小就没有限制。刚好这一题集合的大小不超过64

AC Code:

class Solution {
public:
vector<vector<int> > subsets(vector<int> &S) {
// IMPORTANT: Please reset any member data you declared, as
// the same Solution instance will be reused for each test case.
int len = S.size();
sort(S.begin(), S.end());
vector<vector<int> > res(1);//开始加入一个空集

unsigned long long bit = 1, bitmax = (1<<len);
vector<int> tmpres;
while(bit < bitmax)
{
tmpres.clear();
unsigned long long curBit = bit;
for(int i = 0; i < len; i++)//依次检测前len个二进制位
{
if(curBit & 1)
tmpres.push_back(S[i]);
curBit >>= 1;
}
res.push_back(tmpres);
bit++;
}
return res;
}
};


LeetCode也有类似解法:
My Solution using bit manipulation


AC Code:

class Solution {
public:
    vector<vector<int> > subsets(vector<int> &S) {
        sort (S.begin(), S.end());
        int elem_num = S.size();
        int subset_num = pow (2, elem_num);
        vector<vector<int> > subset_set (subset_num, vector<int>());
        for (int i = 0; i < elem_num; i++)
            for (int j = 0; j < subset_num; j++)
                if ((j >> i) & 1)
                    subset_set[j].push_back (S[i]);
        return subset_set;
    }
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: