力扣刷题Python笔记:组合总和

题目

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

candidates 中的数字可以无限制重复被选取。

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

力扣刷题Python笔记:组合总和_第1张图片
来源:力扣(LeetCode)

python解法

这道题的特殊点在于,所有的元素可以不加限制地重复使用,而不是每个元素只能重复使用一次。

二叉树解法

这道题用到的是二叉树的深度优先遍历解法,以下的解题思路和代码来自于力扣题解。

以示例1为例,我们假设输入 candidates = [2, 3, 6, 7],target = 7。
candidates 数组第一个元素为 2,如果我们能够找到数组中总和为 7 - 2 = 5 的所有组合,再加上 2 ,就是 7 的所有组合;
同理,对于元素 3,如果找到了组合总和为 7 - 3 = 4 的所有组合,再加上 3 ,就是 7 的所有组合,依次这样找下去。
基于以上想法,可以画出如下的树形图。
力扣刷题Python笔记:组合总和_第2张图片
根据上图我们发现,产生的结果中有重复。这是因为在每一个结点做减法、展开分支的时候,由于题目中说“每一个元素可以重复使用”,我因此们考虑了所有的候选数,因此出现了重复的列表。

因此,我们需要对二叉树进行剪枝。根据上面的树形图我们可以发现,如果 target 减去一个数得到负数,那么减去一个更大的树依然是负数,同样搜索不到结果。基于这个想法,我们可以对输入数组进行排序,添加相关逻辑达到剪枝的目的。

代码如下:

def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
    def dfs(candidates, begin, size, path, res, target):
        if target == 0:
            res.append(path)
            return

        for index in range(begin, size):
            residue = target - candidates[index]
            if residue < 0:
                break

            dfs(candidates, index, size, path + [candidates[index]], res, residue)

    size = len(candidates)
    if size == 0:
        return []
    candidates.sort()
    path = []
    res = []
    dfs(candidates, 0, size, path, res, target)
    return res

你可能感兴趣的:(力扣python刷题,算法)