39组合总和
题目:给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的数字可以无限制重复被选取。
说明:所有数字(包括 target)都是正整数。解集不能包含重复的组合。
示例 1:
输入: candidates = [2,3,6,7], target = 7,
所求解集为:[[7],[2,2,3]]
来源:https://leetcode-cn.com/problems/combination-sum/
法一:自己的代码
开始探索算法时,写的一个例子,算法中没有引入控制哪些数参与循环的参数.
class Solution: def combinationSum(self, candidates, target: int): results = [] l = len(candidates) def backtrack(a=[]): if sum(a) == target: results.append(a) return # 这样可以输出结果,但每次回溯的时候都会从2开始计算,导致结果有重复, # 事实上如果从3开始回溯的时候,下次只要继续从3开始就可以了, # 解决的办法是在回溯函数中新增加一个参数k,k中存储下次在数组a中要增加的数 # 可见在回溯算法中,参数的传递非常重要 if sum(a) + 2 <= 8: backtrack(a + [2]) if sum(a) + 3 <= 8: backtrack(a + [3]) if sum(a) + 5 <= 8: backtrack(a + [5]) # if sum(a) + 2 <= 8: # backtrack(a + [2],[2,3,5]) # if sum(a) + 3 <= 8: # backtrack(a + [3],[3,5]) # if sum(a) + 5 <= 8: # backtrack(a + [5],[5]) # 如果用下面的方法进行回溯,append()函数会改变数组a的值,不可用!!! # if sum(a) + 2 <= 8: # a.append(2) # backtrack(a) # if sum(a) + 3 <= 8: # a.append(3) # backtrack(a) # if sum(a) + 5 <= 8: # a.append(5) # backtrack(a) backtrack() print(results) # [[2, 2, 2, 2], [2, 3, 3], [3, 2, 3], [3, 3, 2], [3, 5], [5, 3]] return results if __name__ == "__main__": duixiang = Solution() a = duixiang.combinationSum([2,3,5],8)
改进后的代码:
思路:利用for循环进行控制剪枝,关键是新加的参数控制了回溯函数的起点
class Solution: def combinationSum(self, candidates, target: int): results = [] candidates.sort() def backtrack(a=[], candidates=candidates): if sum(a) == target: results.append(a) return for j,i in enumerate(candidates): if sum(a) + i <= target: # 加入candidates[j:]控制回溯的起点,不加的话每次都是从头开始 # 注意这里的用[]的写法来传递数据,函数结束调用后,不改变candidates的值,这非常重要 backtrack(a + [i], candidates[j:]) # 如果某个数加上后已经大于目标值了,后面的数也就不用试了,直接中断循环 # 前提是要排序 else: break backtrack() print(results) return results if __name__ == "__main__": duixiang = Solution() a = duixiang.combinationSum([1,2],4) print(a)