子集問題,看到這種題,肯定是可以用dfs加遞迴可以做的。首先分析思路,這種類似於全排列的情況,並且順序不同算一種的話,其實就只要遞迴遍歷就可以了
這題其實就是類似於全排列的問題,顯而易見的是順利不同的組合算是乙個,例如[1,2,3], [1,3,2] , 因為陣列中的元素是排序且無重複的,因此只需要考慮在遞迴進入下一階段的時候對輸入的begin+1 就可以了
res=[[
]]for i in
range
(begin,k):)
))dfs(i+
1,temp)
temp.pop(
)
這裡的遞迴最重要的方法是 遞迴向前,若begin 進入的值為0,則下一步就是dfs(1,temp), 由於進入的時候加上了nums[i] 所以回溯的時候必須把之前的最後乙個元素給pop() 掉
class
solution
:def
subsets
(self, nums: list[
int])-
> list[list[
int]]:
res =
for i in
range
(len
(nums)+1
):for tmp in itertools.combinations(nums, i)
:return res
class
solution
:def
subsets
(self, nums: list[
int])-
> list[list[
int]]:
res =[[
]]for i in nums:
res = res +
[[i]
+ num for num in res]
return res
這裡先把相同的問題,子集ii寫出來
初始的版本,未使用剪枝,只是回溯遞迴
# 子集ii
# 思路同樣可以使用回溯遞迴方法
# 與子集i 不同的地方是此時陣列內會有相同元素
k =len(nums)
res=[[
]]nums.sort(
)def
dfs(begin,temp,nums)
:for i in
range
(begin,k)
: )
if temp not
in res:))
dfs(i+
1,temp,nums)
temp.pop(
) dfs(0,
,nums)
return res
顯然這樣的方式速度並不快,於是就要思考如何在出現重複的情況下提前剪枝。
nums.sort(
) self.res =
self.backtrack(
,0, nums,0)
return self.res
defbacktrack
(self, sol, index, nums, pre_used)
:if index ==
len(nums)
:return
ifnot
(index >
0and nums[index]
== nums[index-1]
and pre_used ==0)
: pre_used =
1 self.backtrack(sol+
[nums[index]
], index+
1, nums, pre_used)
pre_used =
0 self.backtrack(sol, index+
1, nums,
0)
這裡的剪枝去掉了對元素的去重判斷,轉而在出現重複之前做剪枝處理,節省空間開支 每日一題 LeetCode
在陣列中的兩個數字,如果前面乙個數字大於後面的數字,則這兩個數字組成乙個逆序對。輸入乙個陣列,求出這個陣列中的逆序對的總數。示例 1 輸入 7,5,6,4 輸出 5 限制 0 陣列長度 50000 思想是 分治演算法 所有的 逆序對 於 3 個部分 左邊區間的逆序對 右邊區間的逆序對 橫跨兩個區間的...
每日一題 合併集合
一共有 n 個數,編號是 1 n,最開始每個數各自在乙個集合中。現在要進行 m 個操作,操作共有兩種 m a b,將編號為 a 和 b 的兩個數所在的集合合併,如果兩個數已經在同乙個集合中,則忽略這個操作 q a b,詢問編號為 a 和 b 的兩個數是否在同乙個集合中 輸入格式 第一行輸入整數 n ...
LeetCode每日一題(題1028)
最近在刷leetcode每日一題,每次做完之後總能有些收穫,所以想著不如每天寫個部落格記錄一下做的題目的解法以及自己寫的時候問題出在 從先序遍歷還原二叉樹 題目大意 給出乙個字串 1 2 3 4 5 6 7 1代表節點的值,前面的 個數代表節點的深度。如果只有乙個子節點,保證這個節點為左子節點。返回...