1. 程式人生 > >【LeetCode & 劍指offer刷題】回溯法與暴力列舉法題7:Subsets(系列)

【LeetCode & 劍指offer刷題】回溯法與暴力列舉法題7:Subsets(系列)

【LeetCode & 劍指offer 刷題筆記】目錄(持續更新中...)

Subsets

Given a set of   distinct   integers,   nums , return all possible subsets (the power set). Note:   The solution set must not contain duplicate subsets.
Example: Input: nums = [1,2,3] Output: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2],
[] ]
C++   //子集問題1:返回一個數組所有子集(不包含重複元素) /* 方法一:遞迴 每個元素,都有兩種選擇,選或不選 增量構造法,深搜,時間複雜度O(2^n),空間複雜度O(n)   需包含空集
*/ /* class Solution { public:     vector<vector<int>> subsets(vector<int>& nums)     {         vector<vector<int>> result;         vector<int> path;         if(nums.empty()) return result;                 sort(nums.begin(), nums.end()); //輸出如果要求有序,需加上此句         subsets(nums, path, 0, result);         return result;     } private:     void subsets(vector<int>& nums, vector<int>& path, int step, vector<vector<int>>& result)     {         if(step == nums.size()) //到達樹末尾時,push當前路徑上元素都結果向量中         {             result.push_back(path);             return;         }              //每一步兩種選擇,構成樹的兩個分支           //不選nums[step]         subsets(nums, path, step+1, result);         //選nums[step]         path.push_back(nums[step]);         subsets(nums, path, step+1, result);         path.pop_back(); //釋放空間,供下個分支存放元素     } };*/ /* 方法二:迭代法 增量構造法 時間複雜度O(2^n),空間複雜度O(1) */       90 .   Subsets II Given a collection of integers that might contain duplicates,   nums , return all possible subsets (the power set). Note:   The solution set must not contain duplicate subsets. Example: Input: [1,2,2] Output: [ [2], [1], [1,2,2], [2,2], [1,2], [] ]
  //子集問題2: 返回一個數組所有子集(可能包含重複元素) /* 遞迴法: subsets I 不同之處在與,每次 dfs push 結果,即每個分支就 push 該路徑,而不是到末尾之後 push 例子: 輸入 [1,2,2], 遞迴樹為     - 1 - 2 -2  []     - 2 - 2 故結果為 [] 1 12 122           2 22 通過限制使每個父結點的子結點元素不相同,從而構造子集 */ /* 方法二:也可以統計每個元素出現的次數,用類似排列2的做法,不過還沒想明白
*/ class Solution { public :     vector < vector < int >> subsetsWithDup ( vector < int >& nums )     {         vector < vector < int >> result ;         vector < int > path ;         if ( nums . empty ()) return result ;                 sort ( nums . begin (), nums . end ()); //必須排序,這樣重複的數才會相鄰         dfs ( nums , 0 , path , result );         return result ;     } private :     //start 為每個父結點的子結點開始的數,子結點取 nums[start~end], 但不能取重複數     void dfs ( vector < int >& nums , int start , vector < int >& path , vector < vector < int >>& result )     {         result . push_back ( path ); //每個結點都push,包括根結點(對應空vector                 for ( int i = start ; i < nums . size (); i ++) // 產生某個父結點的多個子結點 ( 子結點值不能相同 ), 但父結點可以與子結點相同, if 語句中的 i!=start 所起作用         {             if ( i != start && nums [ i ] == nums [ i - 1 ]) continue ; // 如果同一個父結點的當前子結點值與上一個子結點相同,則不執行下面遞迴程式碼,進行分支開闢             path . push_back ( nums [ i ]);             dfs ( nums , i + 1 , path , result ); // 注意這裡傳遞 i+1,類似組合問題的遞迴法             path . pop_back (); // 給下個分支騰出空間         }     }     };