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)
View Code

改进后的代码:

思路:利用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)
View Code

 

 

 

 

 

 

 

posted on 2019-11-26 16:01  吃我一枪  阅读(164)  评论(0编辑  收藏  举报

导航