http://www.cnblogs.com/grandyang/p/4309345.html
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,
IfS=[1,2,3], a solution is:
[
? [3],
? [1],
? [2],
? [1,2,3],
? [1,3],
? [2,3],
? [1,2],
? []
]
這道求子集合的問(wèn)題,由于其要列出所有結(jié)果吓笙,按照以往的經(jīng)驗(yàn)只冻,肯定要是要用遞歸來(lái)做萧落。這道題其實(shí)它的非遞歸解法相對(duì)來(lái)說(shuō)更簡(jiǎn)單一點(diǎn)坏匪,下面我們先來(lái)看非遞歸的解法,由于題目要求子集合中數(shù)字的順序是非降序排列的讥耗,所有我們需要預(yù)處理打厘,先給輸入數(shù)組排序,然后再進(jìn)一步處理秫逝,最開始我在想的時(shí)候恕出,是想按照子集的長(zhǎng)度由少到多全部寫出來(lái),比如子集長(zhǎng)度為0的就是空集违帆,空集是任何集合的子集浙巫,滿足條件,直接加入刷后。下面長(zhǎng)度為1的子集的畴,直接一個(gè)循環(huán)加入所有數(shù)字,子集長(zhǎng)度為2的話可以用兩個(gè)循環(huán)尝胆,但是這種想法到后面就行不通了丧裁,因?yàn)檠h(huán)的個(gè)數(shù)不能無(wú)限的增長(zhǎng),所以我們必須換一種思路含衔。我們可以一位一位的網(wǎng)上疊加煎娇,比如對(duì)于題目中給的例子[1,2,3]來(lái)說(shuō),最開始是空集抱慌,那么我們現(xiàn)在要處理1逊桦,就在空集上加1,為[1]抑进,現(xiàn)在我們有兩個(gè)自己[]和[1]强经,下面我們來(lái)處理2,我們?cè)谥暗淖蛹A(chǔ)上寺渗,每個(gè)都加個(gè)2匿情,可以分別得到[2]兰迫,[1, 2],那么現(xiàn)在所有的子集合為[], [1], [2], [1, 2]炬称,同理處理3的情況可得[3], [1, 3], [2, 3], [1, 2, 3], 再加上之前的子集就是所有的子集合了汁果,代碼如下:
解法一:
// Non-recursionclass Solution {public:
? ? vector > subsets(vector &S) {
? ? ? ? vector > res(1);
? ? ? ? sort(S.begin(), S.end());
? ? ? ? for(inti =0; i < S.size(); ++i) {
? ? ? ? ? ? intsize = res.size();
? ? ? ? ? ? for(intj =0; j < size; ++j) {
? ? ? ? ? ? ? ? res.push_back(res[j]);
? ? ? ? ? ? ? ? res.back().push_back(S[i]);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return res;
? ? }
};
整個(gè)添加的順序?yàn)椋?/p>
[]
[1]
[2]
[1 2]
[3]
[1 3]
[2 3]
[1 2 3]
下面來(lái)看遞歸的解法,相當(dāng)于一種深度優(yōu)先搜索玲躯,參見網(wǎng)友JustDoIt的博客据德,由于原集合每一個(gè)數(shù)字只有兩種狀態(tài),要么存在跷车,要么不存在棘利,那么在構(gòu)造子集時(shí)就有選擇和不選擇兩種情況,所以可以構(gòu)造一棵二叉樹朽缴,左子樹表示選擇該層處理的節(jié)點(diǎn)善玫,右子樹表示不選擇,最終的葉節(jié)點(diǎn)就是所有子集合密强,樹的結(jié)構(gòu)如下:
? ? ? ? ? ? ? ? ? ? ? ? []? ? ? ?
? ? ? ? ? ? ? ? ? /? ? ? ? ? \? ? ? ?
? ? ? ? ? ? ? ? ? /? ? ? ? ? ? \? ?
? ? ? ? ? ? ? ? /? ? ? ? ? ? ? \
? ? ? ? ? ? ? [1]? ? ? ? ? ? ? ? []
? ? ? ? ? /? ? ? \? ? ? ? ? /? ? \
? ? ? ? ? /? ? ? ? \? ? ? ? /? ? ? \? ? ? ?
? ? ? [12]? ? ? [1]? ? ? [2]? ? []
? ? ? /? ? \? ? /? \? ? /? \? ? / \
? [123] [12] [13] [1] [23] [2] [3] []
解法二:
// Recursionclass Solution {public:
? ? vector > subsets(vector &S) {
? ? ? ? vector > res;
? ? ? ? vectorout;
? ? ? ? sort(S.begin(), S.end());
? ? ? ? getSubsets(S, 0,out, res);
? ? ? ? return res;
? ? }
? ? voidgetSubsets(vector &S,intpos, vector &out, vector > &res) {
? ? ? ? res.push_back(out);
? ? ? ? for(inti = pos; i < S.size(); ++i) {
? ? ? ? ? ? out.push_back(S[i]);
? ? ? ? ? ? getSubsets(S, i +1,out, res);
? ? ? ? ? ? out.pop_back();
? ? ? ? }
? ? }
};
整個(gè)添加的順序?yàn)椋?/p>
[]
[1]
[1 2]
[1 2 3]
[1 3]
[2]
[2 3]
[3]
最后我們?cè)賮?lái)看一種解法茅郎,這種解法是CareerCup書上給的一種解法,想法也比較巧妙或渤,把數(shù)組中所有的數(shù)分配一個(gè)狀態(tài)系冗,true表示這個(gè)數(shù)在子集中出現(xiàn),false表示在子集中不出現(xiàn)薪鹦,那么對(duì)于一個(gè)長(zhǎng)度為n的數(shù)組毕谴,每個(gè)數(shù)字都有出現(xiàn)與不出現(xiàn)兩種情況,所以共有2n中情況距芬,那么我們把每種情況都轉(zhuǎn)換出來(lái)就是子集了,我們還是用題目中的例子, [1 2 3]這個(gè)數(shù)組共有8個(gè)子集循帐,每個(gè)子集的序號(hào)的二進(jìn)制表示框仔,把是1的位對(duì)應(yīng)原數(shù)組中的數(shù)字取出來(lái)就是一個(gè)子集,八種情況都取出來(lái)就是所有的子集了拄养,參見代碼如下:
?123Subset
0FFF[]
1FFT3
2FTF2
3FTT23
4TFF1
5TFT13
6TTF12
7TTT123
解法三:
class Solution {public:
? ? vector > subsets(vector &S) {
? ? ? ? vector > res;
? ? ? ? sort(S.begin(), S.end());
? ? ? ? intmax =1<< S.size();
? ? ? ? for(intk =0; k < max; ++k) {
? ? ? ? ? ? vectorout= convertIntToSet(S, k);
? ? ? ? ? ? res.push_back(out);
? ? ? ? }
? ? ? ? return res;
? ? }
? ? vector convertIntToSet(vector &S,int k) {
? ? ? ? vector sub;
? ? ? ? intidx =0;
? ? ? ? for(inti = k; i >0; i >>=1) {
? ? ? ? ? ? if((i &1) ==1) {
? ? ? ? ? ? ? ? sub.push_back(S[idx]);
? ? ? ? ? ? }
? ? ? ? ? ? ++idx;
? ? ? ? }
? ? ? ? return sub;
? ? }
};