給定一個無重複元素的數組 candidates
和一個目標數 target
,找出 candidates
中全部可使數字和爲 target
的組合。web
candidates
中的數字能夠無限制重複被選取。數組
說明:app
全部數字(包括 target
)都是正整數。ide
解集不能包含重複的組合。 函數
因爲最終的結果要求是有序的,所以須要先將數組進行排序;spa
回溯:維持一個路徑組合,而且不斷的將target減去數組中的值,直到target值爲0,則把路徑組合加入到最終的結果中;code
回溯:思路和上面的同樣(思路和1類似,只不過在原來函數的基礎上操做);orm
記憶化搜索:經過字典記錄下每一個和對應的組合,在target在不斷減去數組中的值的時候,若是這個和已經出現過,那麼直接返回該和對應的組合;對象
動態規劃:維護一個的記錄下從1到target每一個值對應的組合的三維數組,一樣的,在target在不斷減去數組中的值的時候,若是這個已經出現過,則能夠經過下標找到對應的組合便可(思路和3類似,一樣是維護每一個和對應的組合);排序
class Solution(object):
def combinationSum(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
res = []
nums_len = len(candidates)
candidates.sort()
def helper(index, target, path):
# 邊界條件爲剩餘關鍵字減到了0,代表path中的值的和已經知足條件
if not target:
res.append(path)
return
for idx in range(index, nums_len):
# 若是剩餘關鍵字比當前數字還要小的話,後面就沒有循環的必要了
# 因此從idx後面的繼續找;
if target >= candidates[idx]:
helper(idx, target - candidates[idx], path + [candidates[idx]])
else:
break
helper(0, target, [])
return res
def combinationSum(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
res = []
candidates.sort()
for idx, num in enumerate(candidates):
if num > target:
break
if num == target:
res.append([num])
break
# 從idx後面遞歸出目標值爲`target - num`的數組,因爲數組是排好序的
# 所以往這些數組中加入num到第一個位置
back_res = self.combinationSum(candidates[idx:], target - num)
for back in back_res:
back.insert(0, num)
res.append(back)
return res
def combinationSum(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
# 記錄每一個和對應的組合
memorize = {}
candidates.sort()
def helper(target):
if target in memorize:
return memorize[target]
new_conbinations = []
for num in candidates:
if num > target:
break
elif num == target:
new_conbinations.append([num])
else:
old_conbinations = helper(target-num)
for conbination in old_conbinations:
if num > conbination[0]:
continue
# 因爲不可以確保num是不是正確的,可以加入到結果數組中,而且數組是可變對象
# 所以不可以將num append 到數組中
# 加入到前面是由於能夠保證順序,這是由於循環是從小到大的順序來找出對應的target
new_conbinations.append([num] + conbination)
memorize[target] = new_conbinations
return new_conbinations
helper(target)
return memorize[target]
def combinationSum(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
# 三維數組,記錄每一個和對應的最終結果
dp = []
candidates.sort()
# cur表明這個下標,也就是這個和,因此從1開始
for cur in range(1, target+1):
conbinations = []
for num in candidates:
if num > cur:
break
elif num == cur:
conbinations.append([cur])
break
else:
# 減去1是由於下標的關係
for conbination in dp[cur-num-1]:
if num > conbination[0]:
continue
conbinations.append([num] + conbination)
dp.append(conbinations)
return dp[target-1]
由於上面求出來的結果中,每一個子數組的排序是亂序的,若是想要最終的順序按照從短到長進行排序,應該怎麼辦呢?
增長當前深度和最大的深度,由於子數組的長度表明着遞歸的深度,所以只要將遞歸的層數從小到大進行排序,那麼就能夠作到最終的結果按照子數組的長度從小到大進行排序了。
class Solution(object):
def combinationSum(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
res = []
nums_len = len(candidates)
candidates.sort()
def helper(index, cur_depth, max_depth, target, path):
# 邊界條件爲到達規定的深度
if cur_depth == max_depth:
if not target:
res.append(path)
return
for idx in range(index, nums_len):
# 若是剩餘關鍵字比當前數字還要小的話,後面就沒有循環的必要了
# 因此從idx後面的繼續找;
if target >= candidates[idx]:
helper(idx, cur_depth + 1, max_depth, target - candidates[idx], path + [candidates[idx]])
else:
break
# target // candidates[0] 是爲了統計最大的深度,由於candidates[0]是最小值
# 所以頂多會有target // candidates[0]個數字進行組合到一塊兒
for depth in range(target // candidates[0] + 1):
helper(0, 0, depth, target, [])
return res
res = Solution().combinationSum([2,3,6,7], 7)
print res # [[7], [2, 2, 3]]