39. 组合总和
如下树形结构如下:
选取第二个数字5之后,剩下的数字要从5、3中取数了,不能再取2了,负责组合就重复了,注意这一点,自己做的时候没想明白这一点
如果是一个集合来求组合的话,就需要startIndex,例如:77.组合 (opens new window),216.组合总和III
如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex,例如:17.电话号码的字母组合
代码如下:
class Solution:def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:result= []path = []self.backtracking(candidates,0,target,path,result)return resultdef backtracking(self,candidates,startIndex,target,path,result):if sum(path) > target:returnif sum(path) == target:result.append(path[:])returnfor i in range(startIndex,len(candidates)):path.append(candidates[i])self.backtracking(candidates,i,target,path,result)path.pop()
剪枝优化
class Solution:def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:result= []path = []candidates.sort() #列表要排序self.backtracking(candidates,0,target,path,result)return resultdef backtracking(self,candidates,startIndex,target,path,result):if sum(path) == target:result.append(path[:])returnfor i in range(startIndex,len(candidates)): #剪枝优化都是在for循环中做优化if sum(path) > target: #如果组合的和比目标值要大就跳出循环break path.append(candidates[i])self.backtracking(candidates,i,target,path,result)path.pop()
40.组合总和II
自己做法:
考虑到把数组排序了,那么在收集数组的时候,也是按照排序来的,所以可以直接return结果:
class Solution:def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:result = []candidates.sort()self.backtrack(candidates,target,0,[],result)return resultdef backtrack(self,candidates,target,startIndex,path,result):if path in result: #直接returnreturnif sum(path) == target:result.append(path[:])returnfor i in range(startIndex,len(candidates)):if sum(path) > target:continuepath.append(candidates[i])self.backtrack(candidates,target,i+1,path,result)path.pop()
代码随想录:
class Solution:def backtracking(self, candidates, target, total, startIndex, path, result):if total == target:result.append(path[:])returnfor i in range(startIndex, len(candidates)):if i > startIndex and candidates[i] == candidates[i - 1]:continueif total + candidates[i] > target:breaktotal += candidates[i]path.append(candidates[i])self.backtracking(candidates, target, total, i + 1, path, result)total -= candidates[i]path.pop()def combinationSum2(self, candidates, target):result = []candidates.sort()self.backtracking(candidates, target, 0, 0, [], result)return result
使用used:
选择过程树形结构如图所示:
class Solution:def backtracking(self, candidates, target, total, startIndex, used, path, result):if total == target:result.append(path[:])returnfor i in range(startIndex, len(candidates)):# 对于相同的数字,只选择第一个未被使用的数字,跳过其他相同数字if i > startIndex and candidates[i] == candidates[i - 1] and not used[i - 1]:continueif total + candidates[i] > target:breaktotal += candidates[i]path.append(candidates[i])used[i] = Trueself.backtracking(candidates, target, total, i + 1, used, path, result)used[i] = Falsetotal -= candidates[i]path.pop()def combinationSum2(self, candidates, target):used = [False] * len(candidates)result = []candidates.sort()self.backtracking(candidates, target, 0, 0, used, [], result)return result