很有意思的一道題,也是很考驗技術的一道題。有兩個方法,乙個遞迴,乙個數學方法。
遞迴
從這個可以看出來,我們依次遍歷整個nums
,每次選擇從nums
中放入或者不放乙個數,因此nums.size()
就是一共要進行多少次抉擇,這裡nums=3
,所以一共要進行2^3=8次抉擇,所以最後會有8個子集。
根據這張圖,我們可以看出,如果要實現這樣乙個抉擇,我們需要使用遞迴的方法,因此這裡我們先假設乙個函式void dfs()
,我們來看看這個函式需要什麼。
函式需要nums
,以及當前需要進行抉擇的那個數字,這裡我們選擇使用這個數字的下標index
;
函式需要乙個返回的值,考慮到我們到最底層才返回,不能每次都返回,我們可以用乙個公共空間儲存,所以我們設定乙個vector>& ret
作為最後的返回的結果;
每次我們做抉擇的時候,我們都需要在上次抉擇完了的基礎上繼續做抉擇,所以我們需要乙個儲存上次抉擇完的結果的變數,也是乙個vectorcurrent
。
所以我們可以設定這個函式為void dfs(vector& nums,int index,vectorcurrent,vector>& ret)
,再觀察退出條件,我們只需要儲存最底層的資料,因此只要到達最底層了我們就向ret
裡面新增一次結果,判斷底層的條件為:index?=nums.size()
,當我們做最後一次抉擇時,index=2
,做完之後index=index+1=3
,這個時候恰好等於nums.size()
。
抉擇的設定:當我們需要進行抉擇的時候,我們有兩個選擇:
不加入當前index
的元素,直接index++
進入下乙個抉擇;
加入當前元素,也就是current.push_back(nums[index])
,然後index++
進入下乙個抉擇。
所以**可以寫成:
vector
int>>
subsets
(vector<
int>
& nums)
;dfs
(nums,
0,current,ret)
;return ret;
}void
dfs(vector<
int>
& nums,
int index,vector<
int> current,vector
int>>
& ret)
dfs(nums,index+
1,current,ret)
; current.
push_back
(nums[index]);
dfs(nums,index+
1,current,ret)
;}
最後的效率為下圖,不太理想,因為呼叫了遞迴,需要大量的空間,並且計算量太複雜了。
2. 注意上面的遞迴的方法,我們一共進行了2^3=8次抉擇,每次往ret
裡面加入乙個資料,這裡我們思考一下0~7
這8個數的二進位制,也就是000~111
,如果我們用某一位為1表示子集中含有該下標對應的數字,那麼101
表示子集為。所以我們只需要遍歷
000~111
這8種情況就行了。
由於每次我們只需要檢查一位是否為1,所以我們用bit masks
,然後每次令被檢查的數向右移一位,然後再次檢查即可。
所以**為:
vector
int>>
subsets2
(vector<
int>
& nums)
;//一共2^n種情況
for(
int i=
0;i<:>
pow(
2,nums.
size()
);++i)
;//只要item還存在就要繼續,直到item==0
while
(item)
ret.
push_back
(temp);}
return ret;
}
效果為下圖,很理想。 leetcode78子集 中等
給定一組不含重複元素的整數陣列 nums,返回該陣列所有可能的子集 冪集 說明 解集不能包含重複的子集。示例 輸入 nums 1,2,3 輸出 3 1 2 1,2,3 1,3 2,3 1,2 要列出陣列的所有子集,因為陣列是不含重複元素的,所以對於每乙個位置的數字,有兩個選擇,選或者不選。可以畫出以...
LeetCode 78 子集 Go 實現
子集 給你乙個整數陣列 nums 陣列中的元素 互不相同 返回該陣列所有可能的子集 冪集 解集 不能 包含重複的子集。你可以按 任意順序 返回解集。示例 1 輸入 nums 1,2,3 輸出 1 2 1,2 3 1,3 2,3 1,2,3 示例 2 輸入 nums 0 輸出 0 func subse...
leetcode 78 子集 回溯法
給定一組不含重複元素的整數陣列 nums,返回該陣列所有可能的子集 冪集 說明 解集不能包含重複的子集。示例 輸入 nums 1,2,3 輸出 3 1 2 1,2,3 1,3 2,3 1,2 class solution return res void recruise vector int num...