首页
/
每日頭條
/
生活
/
去空集的子集個數
去空集的子集個數
更新时间:2026-09-07 14:49:25

問題描述

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

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

示例:

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

輸出:

[

[3],

[1],

[2],

[1,2,3],

[1,3],

[2,3],

[1,2],

[]

]

回溯解決解決

在前面一道題450,什麼叫回溯算法,一看就會,一寫就廢中提到過子集的問題,這裡再來看一下,回溯的模闆如下,就是先選擇,最後再撤銷

private void backtrack("原始參數") { //終止條件(遞歸必須要有終止條件) if ("終止條件") { //一些邏輯操作(可有可無,視情況而定) return; } for (int i = "for循環開始的參數"; i < "for循環結束的參數"; i ) { //一些邏輯操作(可有可無,視情況而定) //做出選擇 //遞歸 backtrack("新的參數"); //一些邏輯操作(可有可無,視情況而定) //撤銷選擇 } }

這道題也一樣,可以把它想象成為一顆n叉樹,通過DFS遍曆這棵n叉樹,他所走過的所有路徑都是子集的一部分,看下代碼

public List<List<Integer>> subsets(int[] nums) { List<List<Integer>> list = new ArrayList<>(); backtrack(list, new ArrayList<>(), nums, 0); return list; } private void backtrack(List<List<Integer>> list, List<Integer> tempList, int[] nums, int start) { //走過的所有路徑都是子集的一部分,所以都要加入到集合中 list.add(new ArrayList<>(tempList)); for (int i = start; i < nums.length; i ) { //做出選擇 tempList.add(nums[i]); //遞歸 backtrack(list, tempList, nums, i 1); //撤銷選擇 tempList.remove(tempList.size() - 1); } }

因為在第450題剛講過這道題,所以基本上沒什麼難度,其實這道題還可以使用位運算解決,來看下

位運算解決

數組中的每一個數字都有選和不選兩種狀态,我們可以用0和1表示,0表示不選,1表示選擇。如果數組的長度是n,那麼子集的數量就是2^n。比如數組長度是3,就有8種可能,分别是

[0,0,0]

[0,0,1]

[0,1,0]

[0,11]

[1,0,0]

[1,0,1]

[11,0]

[111]

這裡參照示例畫個圖來看下

去空集的子集個數(回溯和位運算解子集)1

public static List<List<Integer>> subsets(int[] nums) { //子集的長度是2的nums.length次方,這裡通過移位計算 int length = 1 << nums.length; List<List<Integer>> res = new ArrayList<>(length); //遍曆從0到length中間的所有數字,根據數字中1的位置來找子集 for (int i = 0; i < length; i ) { List<Integer> list = new ArrayList<>(); for (int j = 0; j < nums.length; j ) { //如果數字i的某一個位置是1,就把數組中對 //應的數字添加到集合 if (((i >> j) & 1) == 1) list.add(nums[j]); } res.add(list); } return res; }

非遞歸解決

這題還有其他解題思路,比如先加入一個空集讓他成為新的子集,然後每遍曆一個元素就在原來的子集的後面追加這個值。還以示例來分析下

去空集的子集個數(回溯和位運算解子集)2

public List<List<Integer>> subsets(int[] nums) { List<List<Integer>> res = new ArrayList<>(1 << nums.length); //先添加一個空的集合 res.add(new ArrayList<>()); for (int num : nums) { //每遍曆一個元素就在之前子集中的每個集合追加這個元素,讓他變成新的子集 for (int i = 0, j = res.size(); i < j; i ) { //遍曆之前的子集,重新封裝成一個新的子集 List<Integer> list = new ArrayList<>(res.get(i)); //然後在新的子集後面追加這個元素 list.add(num); //把這個新的子集添加到集合中 res.add(list); } } return res; }

如果非要把它改為遞歸的也是可以的,僅僅提供了一種思路,有興趣的也可以看下

public List<List<Integer>> subsets(int[] nums) { List<List<Integer>> res = new ArrayList<>(1 << nums.length); res.add(new ArrayList<>()); recursion(nums, 0, res); return res; } public static void recursion(int[] nums, int index, List<List<Integer>> res) { //數組中的元素都訪問完了,直接return if (index >= nums.length) return; int size = res.size(); for (int j = 0; j < size; j ) { List<Integer> list = new ArrayList<>(res.get(j)); //然後在新的子集後面追加一個值 list.add(nums[index]); res.add(list); } //遞歸下一個元素 recursion(nums, index 1, res); }

其他解決方式

在426,什麼是遞歸,通過這篇文章,讓你徹底搞懂遞歸中最後講到分支污染的時候提到過這樣一個問題:生成一個2n長的數組,數組的值從0到(2n)-1。我們可以把它想象成為一顆二叉樹,每個節點的子樹都是一個可選一個不可選

去空集的子集個數(回溯和位運算解子集)3

所以我們也可以參照這種方式來寫,代碼如下

public List<List<Integer>> subsets(int[] nums) { List<List<Integer>> res = new ArrayList<>(); helper(res, nums, new ArrayList<>(), 0); return res; } private void helper(List<List<Integer>> res, int[] nums, List<Integer> list, int index) { //終止條件判斷 if (index == nums.length) { res.add(new ArrayList<>(list)); return; } //每一個節點都有兩個分支,一個選一個不選 //走不選這個分支 helper(res, nums, list, index 1); //走選擇這個分支 list.add(nums[index]); helper(res, nums, list, index 1); //撤銷選擇 list.remove(list.size() - 1); }

總結

這題難度不大,但解法比較多,上面介紹的每一種基本上都是一種新的解題思路,如果能全部掌握将會有很大收獲。

去空集的子集個數(回溯和位運算解子集)4

,
Comments
Welcome to tft每日頭條 comments! Please keep conversations courteous and on-topic. To fosterproductive and respectful conversations, you may see comments from our Community Managers.
Sign up to post
Sort by
Show More Comments
推荐阅读
荔枝肉怎麼做好吃又簡單
荔枝肉怎麼做好吃又簡單
1、材料準備裡脊肉350克、番茄醬50克、白糖20克、味精适量、澱粉10克、鹽2克、料酒1勺。2、裡脊肉切成厚片,再剖上十字花刀,然後再改切為小片。3、把肉片用濕澱粉、鹽、料酒、腌制,番茄醬、白醋、白糖、味精、水、濕澱粉調鹵汁待用。4、上漿的肉片卷起來做成荔枝狀,鍋中放肉燒熱,倒入上漿的肉片用勺扒散,炸至金黃熟透,撈出,控幹油分。5、鍋留底油,下入蔥碎,煸下倒入碗汁燒開至粘稠,倒入炸好的荔枝肉翻炒
2026-09-07
說話有點不清楚怎麼辦
說話有點不清楚怎麼辦
1、某些疾病或損傷可以造成說話不清楚,這類問題有很多,先天腭裂大部分雖然比較明顯,但還有一種隐性腭裂...
2026-09-07
窗紗上的油煙用什麼可以洗淨
窗紗上的油煙用什麼可以洗淨
用清水稀釋面粉的方法來清洗。先用開水和面粉以适當比例攪拌成為漿糊水,稍微冷卻後加入适量洗衣粉并攪拌均勻。用紗窗專用毛刷沾上漿糊水刷在紗窗上。然後等待漿糊水晾幹,晾幹後輕輕敲擊緻脫落,油煙和其它污漬就會随漿糊塊一起脫落。窗紗主要用處防止蚊蟲進入,建議在做飯的時候,關上玻璃窗戶,等做飯完成後,再打開玻璃窗,這樣就能防止油煙污漬粘附在窗紗上。
2026-09-07
鹵雞肉怎麼做好吃
鹵雞肉怎麼做好吃
雞1隻、生姜6片、花椒粒15顆、八角2個、香葉3片、蔥兩段、幹紅辣椒3個、生抽30毫升、料酒15毫升、老抽8毫升、白糖10克、鹽4克。1、取新鮮雞一隻,洗幹淨。2、加清水,兩片生姜,煮開,煮到雞肉變色。3、把雞撈出來,重新煮開水,放入雞肉大火燒開,小火慢炖一個小時,放入大棗和生姜片。4、鍋中放油,依次放入生姜,蔥段,花椒,八角,香葉,幹辣椒,小火炒出香味。5、放入兩大勺生抽,一勺料酒,一勺老抽,三
2026-09-07
矽膠擀面墊對人體有害嗎?
矽膠擀面墊對人體有害嗎?
矽膠擀面墊對人體無害。矽膠揉面墊中的無機矽膠是一種高活性吸附材料,通常是用矽酸鈉和硫酸反應,并經老化,酸泡等一系列後處理過程而制得。矽膠屬非晶态物質,不溶于水和任何溶劑,無毒無味,化學性質穩定,除強堿,氫氟酸外不與任何物質發生反應。各種型号的矽膠因其制造方法不同而形成不同的微孔結構。矽膠的化學組份和物理結構,決定了它具有許多其它同類材料難以取代的特點:吸附性能高,熱穩定性好,化學性質穩定,有較高的
2026-09-07
Copyright 2023-2026 - www.tftnews.com All Rights Reserved