leetcode 78題 子集(c++ 三種解法)

題目描述

給定一組不含重複元素的整數數組 nums,返回該數組所有可能的子集(冪集)。

說明:解集不能包含重複的子集。

示例:

輸入: nums = [1,2,3]
輸出:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]

解題思路:

解題思路1(包含三種解題方法):這個我沒看懂作者本人的解題思路,沒看懂樹是怎麼建的

https://blog.csdn.net/camellhf/article/details/73551410

因此找到了解題思路2:是對解題思路1中作者的想法的一個詳細講解

https://www.cnblogs.com/ariel-dreamland/p/9154503.html

建立的樹是這樣的:(來源於第二個鏈接)

                        []
                     /      \
                    /        \
                   /          \        
                  /            \     
                 /              \
              [1]                []
           /       \           /    \
          /         \         /      \        
       [1 2]       [1]       [2]     []
      /     \     /   \     /   \    / \
  [1 2 3] [1 2] [1 3] [1] [2 3] [2] [3] []

第一層爲空集,第二層爲對第一個數的選擇,以此類推。左節點代表選中,右節點代表不選。

代碼:

方法1:用dfs解決,對應解題思路1的第一個方法

注意的點:

1.每次一個數字出棧就相當於選擇了不選擇它的路。

2.爲什麼從第一層開始循環?因爲根節點不存在不選擇它的情況。

3.爲什麼不需要存儲不選擇的情況?因爲在存儲上一層節點值的時候,實際上就是在存儲不選擇的情況,因爲沒到下一層相當於沒選擇。

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> result;
        vector<int> tmp;
        //sort(nums.begin(), nums.end());
        getSub(nums,result,0,tmp);
        return result;
    }
    void getSub(vector<int> s,vector<vector<int>> &result,int layer,vector<int> &tmp)
    {
        result.push_back(tmp);
        for(int i = layer;i < s.size();i++)
        {
            tmp.push_back(s[i]);
            getSub(s,result,i + 1,tmp);
            tmp.pop_back();
        }
    }
    
};

方法2:用bitmap解決,對應解題思路1的第二個方法

感覺原鏈接中的代碼寫的非常棒!

外層循環控制對數組中每個數字的選擇,內層循環是從二進制數000到111所有情況的列舉。

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        
        int bNumber = pow(2,nums.size()); //把二進制數轉化爲十進制 爲2^nums.size() 
        vector<vector<int>> result(bNumber);
        for(int i = 0;i < nums.size();i++)
            for(int j = 0;j < bNumber;j++)
                if(j >> i & 1) //j左移i位(從而判斷數組中第i個元素是否加入子集),結果和1相與(從而只取最低位)
                    result[j].push_back(nums[i]);
        return result;
    }
    
};

方法3:對應解題思路1的第三個方法

即:

第二種解法讓我很驚歎。它是發掘到了一個規律,集合中每添加一個元素,則子集數目增加一倍,且增加的子集爲所有原始子集加上新的元素。舉個例子:nums=[1,2,3] 
1. 初始時集合爲空,子集爲[ [] ]。 
2. 添加一個元素1,即集合爲[1]時,子集爲空集和空集+元素1,即[ [], [1] ]。 
3. 添加下一個元素2,集合爲[1,2],子集除了包含上一步的所有集合還新增了對應集合+元素2的所有集合,即[ [], [1], [2], [1,2]],其中[2]是空集+元素2,[1,2]是[1]+元素2。 
4. 添加下一個元素3,集合爲[1,2,3],類似的得到子集爲[ [], [1], [2], [1,2], [3], [1,3], [2,3], [1,2,3] ],其中[3]是空集+元素3,[1,3]是[1]+元素3,[2,3]是[2]+元素3,[1,2,3]是[1,2]+元素3。
(來源於第一個鏈接)

 

class Solution {
public:
	vector<vector<int>> subsets(vector<int>& nums) {
		vector<vector<int>> result;
		vector<int> empty;
		result.push_back(empty);
		for (int i = 0; i < nums.size(); i++)
		{
			int result_size = result.size();//進入循環前存儲在添加前的結果長度 因爲添加後長度會變
			for (int j = 0; j < result_size; j++)
			{
				vector<int> tmp = result[j];
                tmp.push_back(nums[i]);
                result.push_back(tmp);
			}
		}
		return result;
	}

};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章