39. 组合总和

Posted 炫云云

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了39. 组合总和相关的知识,希望对你有一定的参考价值。

39. 组合总和

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

candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是唯一的。

对于给定的输入,保证和为 target 的唯一组合数少于 150 个。

示例

输入: candidates = [2,3,6,7], target = 7
输出: [[7],[2,2,3]]

输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]

输入: candidates = [2], target = 1
输出: []

输入: candidates = [1], target = 1
输出: [[1]]

回溯算法

回溯算法 python

根据示例 1:输入: candidates = [2, 3, 6, 7]target = 7

  • 候选数组里有 2,如果找到了组合总和为 7 - 2 = 5 的所有组合,再在之前加上 2 ,就是 7 的所有组合;
  • 同理考虑 3,如果找到了组合总和为 7 - 3 = 4 的所有组合,再在之前加上 3 ,就是 7 的所有组合,依次这样找下去。

通过回溯算法找出所有组合:

  • target = 7根结点 ,创建一个分支的时 做减法
  • 每一个箭头表示:从父亲结点的数值减去边上的数值,得到孩子结点的数值。边的值就是题目中给出的 candidate 数组的每个元素的值;
  • 减到 0或者负数的时候停止,即:结点 0 和负数结点成为叶子结点;
  • 所有从根结点到结点 0的路径(只能从上往下,没有回路)就是题目要找的一个结果。

析重复路径产生的原因

产生重复的原因是:在每一个结点,做减法,展开分支的时候,由于题目中说 每一个元素可以重复使用,我们考虑了 所有的 候选数,因此出现了重复的列表。

可不可以在搜索的时候就去重呢?答案是可以的。遇到这一类相同元素不计算顺序的问题,我们在搜索的时候就需要 按某种顺序搜索

具体的做法是:每一次搜索的时候设置 下一轮搜索的起点 index,已经考虑过的数,以后的搜索中就不能出现,让我们的每次搜索都从当前起点往后搜索(包含当前起点),直到搜索到数组末尾。这样我们人为规定了一个搜索顺序,就可以避免重复方案。

即:从每一层的第 2 个结点开始,都不能再搜索产生同一层结点已经使用过的 candidate 里的元素。

算法

定义递归函数 dfs(target, index) 表示当前在 candidates 数组的第 index 位,还剩 target 要组合,已经组合的列表为 combine。递归的终止条件为 target <= 0 或者 candidates 数组被全部用完。

那么在当前的函数中,每次我们可以选择跳过不用第 index 个数,即执行 dfs(target, index+ 1)

也可以选择使用第 index 个数,即执行 dfs(target - candidates[index], index),注意到每个数字可以被无限制重复选取,因此搜索的下标仍为 index

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        n = len(candidates)
        combine =[]
        ans= []
        def dfs(target , index):
            if index == n:
                return
            if target ==0:
                ans.append(combine[:])
                return 
            # 选择当前数,即重复选择
            if target - candidates[index] >=0:
                combine.append(candidates[index])
                dfs(target- candidates[index],index)
                combine.pop()

            dfs(target, index+1) # 直接跳过

        dfs(target, 0)
        return ans
class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        n = len(candidates)
        combine =[]
        ans= []
        def dfs(target , index):
            if index == n:
                return
            if target ==0: # 等于零说明结果符合要求
                ans.append(combine[:])
                return 
            for i in range(index, n): # 等于零说明结果符合要求
                # 如果candidates大于目标值,则差为负数,不符合结果
                if target - candidates[i] >=0:
                    combine.append(candidates[i])
                    dfs(target- candidates[i],i) # 目标值减去元素值
                    combine.pop()

        dfs(target, 0)
        return ans

以上是关于39. 组合总和的主要内容,如果未能解决你的问题,请参考以下文章

leetcode-----39. 组合总和

leetcode 39. 组合总和---回溯篇2

精选力扣500题 第70题 39. 组合总和c++/java详细题解

39. 组合总和

39. 组合总和

39. 组合总和回溯Normal