解答:
方法一:選or不選的dfs(輸入視角)
思路:[1,2,3]的全部子集可以看成是對數組的每一位數字做選擇。
eg.空集就是一個數字都不選,[1,2]就是1,2選,3不選。
class Solution {
public:vector<vector<int>> res;//存所有結果用的vector<int> path;//存單個結果void dfs(vector<int>&nums,int pos,int size){if(pos==size){//遍歷到了數組的最后,做完了所有的選擇,為什么size是n前面的日記解釋過了~res.emplace_back(path);//把單個結果放進總結果里面,注意emplace_back函數,之前也出現過幾次了return;}//對于單個數字,我們的選擇有兩種//1.選path.push_back(nums[pos]);//放進單個數組dfs(nums,pos+1,size);//做好選擇后再去做下一個選擇path.pop_back();//回溯的精髓,恢復原狀//2.不選dfs(nums,pos+1,size);//直接做下一個選擇 }vector<vector<int>> subsets(vector<int>& nums) {int size=nums.size();dfs(nums,0,size);return res;}
};
時間復雜度:O(n2^n)
空間復雜度:O(n)
方法二:選or不選的dfs(輸出視角)
思路:如果選了數組的某一位添加到答案末尾,那么下一個要添加到答案末尾的數,就要在這個某一位后面的數字中枚舉了。用循環來幫忙
舉個例子哦,對于子集[1,2,3]來說,從1開始思考,1要不要在我的子集里面,要的話那就放進去,不要的話那就恢復現場
再接著考慮下一位2……
class Solution {
public:vector<vector<int>> res;//存所有結果用的vector<int> path;//存單個結果void dfs(vector<int>&nums,int pos,int size){res.emplace_back(path);//每次做完這個數要不要選的結果都放進去總結果里面//從path的當前位置開始考慮要不要選for(int i=pos;i<size;i++){path.push_back(nums[i]);//要選dfs(nums,i+1,size);//下一個開始選擇path.pop_back();//恢復現場}}vector<vector<int>> subsets(vector<int>& nums) {int size=nums.size();dfs(nums,0,size);return res;}
};
時間復雜度:O(n2^n)
空間復雜度:O(n)
方法三:二進制枚舉
使用位運算來高效枚舉所有可能的組合
比如[1,2,3],我們枚舉xxx所有的二進制可能(000,001,010……)如果是000就是空集,001就是把3放進去,010就是放2……
二進制數對應的這一位是1就相當于選這位數,0就是不選。
class Solution {
public:vector<vector<int>> subsets(vector<int>& nums) {int n=nums.size();vector<vector<int>> res(1<<n);//一共1<<n種結果//i是結果數,j是位數for(int i=0;i<(1<<n);i++){for(int j=0;j<n;j++){// 判斷第j位是否為1if(i>>j&1)res[i].push_back(nums[j]);//是1的話就放進去結果}} return res;}
};
時間復雜度:O(n2^n)
空間復雜度:O(1)