代码随想录 - Day32 - 回溯:组合问题

代码随想录 - Day32 - 回溯:组合问题

39. 组合总和

做题的时候遇到一点疑问:
为什么必须是result.append(path[:])而不能写成result.append(path)呢?
原因:
result.append(path)result中添加的是path这个参数,后续如果path发生改变,那么result中的值也会跟着一起发生改变。
result.append(path[:])是把一个新的list添加到result中,后续path的改变不会影响result中的值。

class Solution:
    def backtracking(self, startIndex, currentSum, path, result, target, candidates):
        if currentSum > target:
            return
        if currentSum == target:
            result.append(path[:])  # 必须是 result.append(path[:])
            return
        for i in range(startIndex, len(candidates)):
            currentSum += candidates[i]
            path.append(candidates[i])
            self.backtracking(i, currentSum, path, result, target,candidates)
            currentSum -= candidates[i]
            path.pop()

    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        result = []
        self.backtracking(0, 0, [], result, target, candidates)
        return result

想到了怎么剪枝但是代码一直写不到一块,看了题解才知道应该写到 for 循环里

lass Solution:
    def backtracking(self, startIndex, currentSum, path, result, target, candidates):
        if currentSum > target:
            return
        if currentSum == target:
            result.append(path[:])
            return
        for i in range(startIndex, len(candidates)):
            if currentSum + candidates[startIndex] > target:    # 剪枝
                return
            currentSum += candidates[i]
            path.append(candidates[i])
            self.backtracking(i, currentSum, path, result, target,candidates)
            currentSum -= candidates[i]
            path.pop()   

    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        result = []
        candidates.sort()   # 必须给 candidates 排序一下,因为题目中并没有说 candidates 中元素是按照从小到大的顺序的
        self.backtracking(0, 0, [], result, target, candidates)
        return result

40. 组合总和 II

要想到的问题:
candidates中的元素并非有序 好解决,用sort()就可以了
candidates中的元素可以重复,重复元素会出现相同path,要排除该情况 卡在这一步了
这道题在去重的地方有些复杂,画个图:

candidates = [1,1,2]
target = 3
取1
取1
去重,不走这块,直接跳过
取2
取1
取2
取2
和前面遍历过的path重复了
所以不遍历这块
取2
currentSum > target
结束
[1,1,2]中取一个数
currentSum == 1
path == [1]
在[1,2]中取一个数
currentSum == 1
path == [1]
continue跳过
currentSum == 2
path == [2]
在[]中取一个数
return
currentSum == 2
path == [1,1]
在[2]中取一个数
currentSum == 3
path == [1,2]
在[]中取一个数
return
currentSum == 4
path == [1,1,2]

虚线的部分是没有遍历的,画出来只是为了更方便理解。
从图中可以直观的看出,要去重的是同一树层上相同的元素,而不是同一树枝上相同的元素的

class Solution:
    def backtracking(self, startIndex, currentSum, target, candidates, result, path):
        if currentSum > target:
            return
        if currentSum == target:
            result.append(path[:])
            return
        for i in range(startIndex, len(candidates)):
            if currentSum + candidates[i] > target:    # 剪枝
                return
            # 对同一树层使用过的元素进行跳过
            if i > startIndex and candidates[i - 1] == candidates[i]:
                continue
            currentSum += candidates[i]
            path.append(candidates[i])
            self.backtracking(i + 1, currentSum, target, candidates, result, path)
            currentSum -= candidates[i]
            path.pop()

    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        candidates.sort()   # 排序
        result = []
        self.backtracking(0, 0, target, candidates, result, [])
        return result

今天第二道题用了好长时间,这种题怎么能是中等?!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值