這題要從一個可能包含重複數字的整數陣列中,返回所有可能的「子集」(就是「冪集」),要注意的是,解集不能包含重複的子集。
想法:
這個問題的重點在怎麼處理重複元素,確保生成的子集不重複,可以用 回溯法生成所有子集。
步驟:
先把 nums 排序,這樣重複的元素就會相鄰,幫助在生成子集時重複,回溯法生成子集,用回溯法遞迴建子集,對每個數字,有兩個選擇,要麼把它加入當前子集,要麼不加(回溯法會探索每一種可能性),避免重複子集,在回溯的過程,如果當前數字跟前一個數字一樣,且前一個數字還沒被加入過,就跳過這個數字,避免產生重複的子集。
程式碼:
class Solution(object):
def subsetsWithDup(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
#結果變數,存所有子集
res = []
#把輸入的數組排序,便於後面判斷重複元素
nums.sort()
#回溯函數,current是當前的子集,start是從哪個索引開始遞迴
def backtrack(current, start):
# 把當前生成的子集加入結果
res.append(list(current))
#從start索引開始,遞迴遍歷每個數字
for i in range(start, len(nums)):
# 如果當前數字和上一個數字同,就跳過,避免重複
if i > start and nums[i] == nums[i - 1]:
continue
#選擇當前數字,把它加入子集
current.append(nums[i])
#繼續遞迴生成下一層子集
backtrack(current, i + 1)
#撤銷選擇(回溯),把剛加入的數字移除,進行下一個可能的選擇
current.pop()
#從空集開始回溯
backtrack([], 0)
return res
時間複雜度:由於生成的子集數量是2的n次方(其中 n 為 nums 的長度),而且每個子集可能最多包含 n 個元素,因此時間複雜度大約是O(n成2的n次方)
心得:
這類用回溯法解決的問題,幫我了解遞迴及決策樹的思考方式,回溯法讓我能通過不同的選擇路徑來解決問題,同時學會怎樣在過程中「剪枝」提高效率,另外,處理包含重複元素的集合,讓我了解排序的重要性,它可以簡化處理重複元素的邏輯。