力扣78題:給定一組不含重複元素的整數陣列 nums,返回該陣列所有可能的子集(冪集)。
這題的兩種做法:
1.遞迴法:
遞迴法中最主要的思想是要弄懂 為什麼可以用這種方法實現這道題;
通過從空集開始不斷遞迴到集合中最後一個元素,
比如有陣列[1,2,3] ,首先設定一個最終的大集合 ;
因為空集是每個集合的子集,所以先把空集加入(這個演算法的最重要的點) 此時大集合可以看作 [ [空集]]
然後遍歷陣列[1,2,3],先從1開始,用1和空集合併為一個新的
子集[[1],[]]也就[1];(特別注意的是每次遍歷一個數字後就複製一次用來拼接下一個元素)
此時大集合內的子集為[ [],[1] ];
複製一次用來遍歷下一個元素
把數組裡的第二個元素2拼接到複製來的陣列中形成[[],[2]]和[ [1],[2] ]也就是[2]和[ [1],[2] ]
通過addAll()方法把[2]和[ [1],[2] ]加入到大集合中,
此時大集合就為[ [], [1], [2],[[1],[2]], ]
使用同上的方法把3也拼接到複製來的陣列中得到[ [3], [1,3], [[1],[2],[3]]],把他加入到大集合中就得到了最終子集和
[ [], [1], [2],[[1],[2]],[3], [1,3], [[1],[2],[3]] ]
2. 回溯法:
回溯法最主要要明白的是backtrack方法的作用,因為回溯法是通過深度優先的方法來不斷探索全部解,從中找出正確的解
backtrack方法中的k代表的是要找出子集的長度,子集的長度範圍為num.length,所以只要
然後看backtrack方法,當k==0時,代表構造的子集長度為0也就是空集,當k大於0時,比如k=1時
第一遍的時候k為1 ,開始位置start為0,也就是從[1,2,3]中的1開始,把[1]加入cur陣列中(這裡的cur充當工具人不斷的重複利用來幫忙傳遞子集)
,然後到了下一步把 start+1,k-1; 這裡start+1的目的是因為陣列nums下標為0的元素已經放在了cur中,要+1從下一個元素開始,k-1是因為k代表構造子集的長度,既然已經加了一個元素,所以需要長度要減少1;這裡因為k為1所有k-1後為0,所以可以直接加入大集合中;
然後cur.remove(cur.size()-1)的目的是為了讓cur清除剛剛的資料更好的充當工具人;(這裡有趣的是如果k的值夠大,會多次從經過迴圈裡的backtrack(無線套娃),當最終的backtrack走完時,上面的backtrack也會跟著走完,直到第一個,cur.remove()也會逐個執行,所以不用擔心最後cur沒有清除乾淨)