每天一道算法题:39.组合总和

难度

中等

题目

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有_ _不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。

示例 1:

输入:candidates = [2,3,6,7], target = 7 输出:[[2,2,3],[7]] 解释: 2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。 7 也是一个候选, 7 = 7 。 仅有这两种组合。
示例 2:
输入: candidates = [2,3,5], target = 8 输出: [[2,2,2,2],[2,3,3],[3,5]]
示例 3:
输入: candidates = [2], target = 1 输出: []

提示:

1 <= candidates.length <= 30
2 <= candidates[i] <= 40
candidates 的所有元素 互不相同
1 <= target <= 40

思路

使用回溯大法,我们总结的回溯就是横向遍历的同时纵向遍历。for 循环是横向遍历,递归则是纵向遍历。
具体递归的时候,每一层的元素不能重复,去一层的是就不能选了,所以 for 循环需要标记下开始位置,以便于下一层遍历的开始位置都是,当前元素的下一位。所以递归的时候就要传递给下一层开始循环的位置。
此题递归过程中,需要判断当前所选的值是否满足条件,即是否小于或等于目标值,如果进行递归操作,如果不满足直接跳过。

代码

2 3 6 7
7

要求 每一个组合中的元素时可以重复的,但是不能有重复的组合
每次选择一个元素后,去下一层遍历的时候,就不能再选这个元素了


第1层选2 第2层可以继续选2 第3层还能选2 第4层的时候 2+2+2+2=8 大于 目标值7了 不符合所以跳过,
                                   第4层选 3 6 7 的时候结果都是大于7的 都不符合
2 2 2 2
2 2 2 3
2 2 2 6
2 2 2 7

第4层的时候所有的元素都不符合,所以回溯到第3层
第3层选3 刚好 2+2+3=7满足条件 记录下来
第3层选6 7 都大于7 不符合

2 2 3   #
2 2 6
2 2 7

回溯到第2层 2的所有情况已经完了,所以接下来从3开始,
此时第3层的 选择2 和组合结果 2 2 3 重复了,不能记录,
这种处理办法就是,在去下一层的时候,只能从当前的元素开始,不能取前面的,所以每次遍历的时候就给 一个初始位置
2 3 2   # 重复了
2 3 3
2 3 6
2 3 7

2 6
2 7


3 2 2   # 重复了
3 2 3
3 2 6
3 2 7

3 3 2
3 3 3
3 3 6
3 3 7

3 6
3 7

6 3
6 7

7       #


"""


class Solution:
    def combinationSum(self, candidates, target):
        self.candidates = candidates
        self.target = target
        self.length = len(self.candidates)
        self.reault = []
        # self.position = [False] * self.length
        self.backtrack(0, [], self.target)
        print(self.reault)
        return self.reault

    def backtrack(self, start, tmp, target):
        # start  表示每层遍历的开始位置
        # tmp 存元素的临时栈,每递归一层 就入栈一个元素,递归完成后,则弹出栈顶元素 可以实现回溯
        # target 目标值,为0时就达到目的,结束递归

        # 终止条件 当目标值为0的时候,就终止递归
        if target == 0:
            self.reault.append(tmp[:])
            return
        # 在每一层用过的元素就不会再用了,所以需要记录下每层的开始位置
        for i in range(start, self.length):

            # 因为每个元素可以重复使用,所以对于各元素来说,不需要去重
            # 但是需要满足条件,就是当前所选的值,一定要小于等于目标时,才能选择,并去下一层再试探
            if target >= self.candidates[i]:
                tmp.append(self.candidates[i])
                # 在不同层中,可以使用相同的元素,所以使用i 说明在下一层试探的时候,还可以选择当前的元素
                # start 表示在同一层遍历的时候的开始位置,i表示在下一层开始位置
                self.backtrack(i, tmp, target - self.candidates[i])
                tmp.pop()


if __name__ == '__main__':
    candidates = [2, 3, 6, 7]
    target = 7
    candidates = [2, 3, 5]
    target = 8
    s = Solution()
    s.combinationSum(candidates, target)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骇客567

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值