描述
給定一個含不同整數的集合,返回其所有的子集
子集中的元素排列必須是非降序的,解集必須不包含重複的子集
您在真實的面試中是否遇到過這個題? 是
樣例
如果 S = [1,2,3]
,有如下的解:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
挑戰
你可以同時用遞歸與非遞歸的方式解決麼?
遞歸的方法:
不要去想遞歸是如何一層一層調用的,而是要想如果解決當前問題,找到遞歸的出口
可以這樣思考,由於原集合每一個數字只有兩種狀態,要麼存在,要麼不存在,那麼在構造子集時就有選擇和不選擇兩種情況,所以可以構造一棵二叉樹,左子樹表示選擇該層處理的節點,右子樹表示不選擇,最終的葉節點就是所有子集合,樹的結構如下:
[]
/ \
/ \
/ \
[1] []
/ \ / \
/ \ / \
[1 2] [1] [2] []
/ \ / \ / \ / \
[1 2 3] [1 2] [1 3] [1] [2 3] [2] [3] []
代碼如下:
class Solution {
public:
/**
* @param nums: A set of numbers
* @return: A list of lists
*/
vector<vector<int>> subsets(vector<int> &nums) {
// write your code here
//這裏排序並不必須,只是爲了子集中元素以遞增排序
sort(nums.begin(), nums.end());
vector<vector<int>> subs;
vector<int> sub;
genSubsets(nums, 0, sub, subs);
return subs;
}
void genSubsets(vector<int>& nums, int start, vector<int>& sub, vector<vector<int>>& subs) {
//我們發現這裏好像並沒有遞歸出口,因爲終止條件由下面for循環控制
subs.push_back(sub);
for (int i = start; i < nums.size(); i++) {
//情況一:子集包含元素nums[i]
sub.push_back(nums[i]);
//爲何是i+1,因爲已經解決了第i個元素,需要遞歸從第i+1個元素開始求解
genSubsets(nums, i + 1, sub, subs);
//情況二:子集不包含nums[i],即略過第i個元素
//可以想象,不去管上一條遞歸語句,當下一次循環到i+1時,第i個元素已經略過
sub.pop_back();
}
}
};
二:含有重複元素的子集合
For example,
If S = [1,2,2]
, a solution is:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
思想:根據上面子集合 裏的構建樹的方法,在處理到第二個2時,由於前面已經處理了一次2,這次我們只在添加過2的[2] 和 [1 2]後面添加2,其他的都不添加,那麼這樣構成的二叉樹如下圖所示:
[]
/ \
/ \
/ \
[1] []
/ \ / \
/ \ / \
[1 2] [1] [2] []
/ \ / \ / \ / \
[1 2 2] [1 2] X [1] [2 2] [2] X []
class Solution {
public:
/**
* @param nums: A set of numbers
* @return: A list of lists
*/
vector<vector<int>> subsets(vector<int> &nums) {
// write your code here
//這裏排序並不必須,只是爲了子集中元素以遞增排序
sort(nums.begin(), nums.end());
vector<vector<int>> subs;
vector<int> sub;
genSubsets(nums, 0, sub, subs);
return subs;
}
void genSubsets(vector<int>& nums, int start, vector<int>& sub, vector<vector<int>>& subs) {
//我們發現這裏好像並沒有遞歸出口,因爲終止條件由下面for循環控制
subs.push_back(sub);
for (int i = start; i < nums.size(); i++) {
//情況一:子集包含元素nums[i]
sub.push_back(nums[i]);
//爲何是i+1,因爲已經解決了第i個元素,需要遞歸從第i+1個元素開始求解
genSubsets(nums, i + 1, sub, subs);
//情況二:子集不包含nums[i],即略過第i個元素
//可以想象,不去管上一條遞歸語句,當下一次循環到i+1時,第i個元素已經略過
sub.pop_back();
while(i+1<nums.size()&&nums[i]==nums[i+1]) ++i;
}
}
};