leetcode39_组合总数

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的数字可以无限制重复被选取。

说明:

所有数字(包括 target)都是正整数。
解集不能包含重复的组合。

示例 1:

输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]

示例 2:

输入: candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]

这道题目是求集合,并不是求极值,因此动态规划不是特别切合。这种题目其实有一个通用的解法,就是回溯法,回溯法其实来源于深度优先搜索dfs,模板:
1, 以当前位置为源流往下摸排所有可以跳到的位置
2, 最终递归返回源流位置
3, 然后再以下面一个位置作为源流位置,重复上述操作

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        # 先排序,便于后面剪枝
        candidates.sort()
        # 最终结果集合
        res = []
        # temp用来记录路径
        temp = []
        self.dfs(res,candidates, temp, target, 0)
        return res
        
   # 记住回溯法的模板
    def dfs(self, res, candidates, temp, target, index):
        # target为剩余和,从candidates的index开始往下摸排,temp为路径记录
        # 递归边界
        # 当满足节点和等于target的时候(剩余和=0),
        # 此时路径中的所有节点可以算是一条符合要求的路径,可加入最终结果集合,
        # 然后return
        if target == 0:
            res.append(temp.copy())
            return
        # 剪枝
        # 因为事先已经排序过了,所以当剩余和为负数的时候(路径中最后一个节点,
        # 也就是最大的那个,如果都比剩余和大的话,剩余要摸排的也就是index及以后的节点,
        # 会更大,导致剩余和为负),
        # 再往下摸排只会让剩余和越来越小,此时不需要再往下查找了,return
        elif (temp and target < temp[-1]):
            return
        for i in range(index, len(candidates), 1):
            # 把当前节点加入路径
            temp.append(candidates[i])
            # 以这个节点为源往下摸排,看看再加入哪些节点能满足节点和等于target
            self.dfs(res, candidates, temp, target-candidates[i], i) 
            # 这条源流摸排结束,将这个节点弹出,再加入下一个节点并以此为源重新往下摸排
            temp.pop()
发布了31 篇原创文章 · 获赞 18 · 访问量 6019

猜你喜欢

转载自blog.csdn.net/weixin_40027284/article/details/104797891