- 組合總和
本題是 集合裡元素可以用無數次,那麼和組合問題的差別 其實僅在於 startIndex上的控制
題目連結/文章講解:https://programmercarl.com/0039.組合總和.html
影片講解:https://www.bilibili.com/video/BV1KT4y1M7HJ
給定一個無重複元素的陣列 candidates 和一個目標數 target ,找出 candidates 中所有可以使數字和為 target 的組合。
candidates 中的數字可以無限制重複被選取。
思考
這道題的特點是可以重複選取。
因此for迴圈內遍歷的時候,start_index = i
class Solution:
def __init__(self):
self.path = []
self.res_list_all = []
self.sum = 0
def backtracking(self,candidates,target,start_index):
if self.sum == target:
self.res_list_all.append(self.path[:])
return
elif self.sum > target:
return
else:
for i in range(start_index,len(candidates)):
self.path.append(candidates[i])
self.sum+=candidates[i]
self.backtracking(candidates,target,i)
self.path.pop()
self.sum-=candidates[i]
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
self.backtracking(candidates,target,0)
return self.res_list_all
排序後,回溯的過程可以剪枝,同一層,前面的數和已經超了的話,後面的就不用再試了,因為後面的數更大。
class Solution:
def __init__(self):
self.path = []
self.res_list_all = []
self.sum = 0
def backtracking(self,candidates,target,start_index):
if self.sum == target:
self.res_list_all.append(self.path[:])
return
elif self.sum > target:
return
else:
for i in range(start_index,len(candidates)):
if self.sum+candidates[i] > target:
break
self.path.append(candidates[i])
self.sum+=candidates[i]
self.backtracking(candidates,target,i)
self.path.pop()
self.sum-=candidates[i]
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
candidates.sort()
self.backtracking(candidates,target,0)
return self.res_list_all
40.組合總和II
本題開始涉及到一個問題了:去重。
注意題目中給我們 集合是有重複元素的,那麼求出來的 組合有可能重複,但題目要求不能有重複組合。
題目連結/文章講解:https://programmercarl.com/0040.組合總和II.html
影片講解:https://www.bilibili.com/video/BV12V4y1V73A
給定一個候選人編號的集合 candidates 和一個目標數 target ,找出 candidates 中所有可以使數字和為 target 的組合。
candidates 中的每個數字在每個組合中只能使用 一次 。
注意:解集不能包含重複的組合。
思考
這道題的難點是要在回溯中去重,即去除重複的組合。
兩種方法:
- 需要定義一個used陣列。
used[i - 1] == true,說明同一樹枝candidates[i - 1]使用過
used[i - 1] == false,說明同一樹層candidates[i - 1]使用過
2. 判斷條件增加i>start_index
兩種方案都需要先排序才能去重。
方案二的方法
class Solution:
def __init__(self):
self.res = []
self.res_all = []
self.sum = 0
def backtracking(self,candidates,target,start_index):
if self.sum > target:
return
if self.sum == target:
self.res_all.append(self.res[:])
return
for i in range(start_index,len(candidates)):
if i > start_index and (candidates[i-1] == candidates[i]):
continue
self.sum+=candidates[i]
self.res.append(candidates[i])
self.backtracking(candidates,target,i+1)
self.res.pop()
self.sum-=candidates[i]
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
candidates.sort()
self.backtracking(candidates,target,0)
return self.res_all
131.分割回文串
本題較難,大家先看影片來理解 分割問題,明天還會有一道分割問題,先打打基礎。
https://programmercarl.com/0131.分割回文串.html
影片講解:https://www.bilibili.com/video/BV1c54y1e7k6
給定一個字串 s,將 s 分割成一些子串,使每個子串都是迴文串。
返回 s 所有可能的分割方案。
示例: 輸入: "aab" 輸出: [ ["aa","b"], ["a","a","b"] ]
思考
分割問題本質上也是求組合問題。start_index表示分割線。
def is_huiwen(s):
i = 0
j = len(s)-1
while i<j:
if s[i]==s[j]:
i+=1
j-=1
else:
return False
return True
class Solution:
def partition(self, s: str) -> List[List[str]]:
def backtracking(s,star_index):
if star_index == len(s):
res.append(path[:])
return
for i in range(star_index,len(s)):
if is_huiwen(s[star_index:i+1]):
path.append(s[star_index:i+1])
backtracking(s,i+1)
path.pop()
path = []
res = []
backtracking(s,0)
return res