代码随想录算法训练营day25|leetcode39,40

Leetcode39

39. 组合总和 - 力扣(Leetcode)

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

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

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

思路:这道题和我们之前做过的组合题很类似,只不过这里有一个条件是,同一个数字可以无限制的重复使用,还记得我们之前题目中的递归参数写i的时候都是写的i+1,这就是直接i递归下一层,就是不会再次使用当前的数字,但是这里既然要求可以重复使用,那么就不用i+1了,直接递归i就可以了。

 递归三部曲:

        循环终止条件:

        递归参数:一个startindex控制for循环的起始位置,sum用于求和,判断是否达到目标值。

那么对于组合问题,什么时候需要startIndex呢?

如果是一个集合来求组合的话,就需要startIndex,例如:77.组合 (opens new window)216.组合总和III (opens new window)

如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex,例如:17.电话号码的字母组合

        单层循环逻辑:单层for循环依然是从startIndex开始,搜索candidates集合。注意:本题元素为可重复选取的

所以我们的i 可以不用写成i+1

代码:

def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        path = []
        result =  []
        def traversal(candidates,target,sum,index):
            if sum > target:
                return 
            if sum==target:
                result.append(path[:])
                return 
            for i in range(index,len(candidates)):
                sum+=candidates[i]
                path.append(candidates[i])
                traversal(candidates,target,sum,i)
                sum-=candidates[i]
                path.pop()
        traversal(candidates,target,0,0)
        return result

 

Leetcode40组合总和

40. 组合总和 II - 力扣(Leetcode)

思路:本题的难点在于区别2中:集合(数组candidates)有重复元素,但还不能有重复的组合

  1. 本题candidates 中的每个数字在每个组合中只能使用一次。
  2. 本题数组candidates的元素是有重复的,而39.组合总和 (opens new window)是无重复元素的数组candidates

这道题对比上面这道题多了一个限制,也就是只能使用一次,但是这个使用一次是怎么理解的呢?

我们转化为树形结构来看,有两个维度,一个是树的同一层,另一个是树的分支,也就是说树的分是可以取重复的,但是在树的同一层中,之前用过的就不能再用第二次了。

如图所示:

强调一下,树层去重的话,需要对数组排序!

回溯三部曲:

                递归参数:这里还是设置一个index,然后一个sum来记录求和

                递归终止条件:如果sum+candidates[I]>target,注意我们的数组已经是排好序了的,那么如果开头加上就已经大于target了,后面的也只会更大,就不用再继续了。

                单层循环逻辑:如果循环到当前元素,判断是否和前面的元素一样,并且这里的i是大于0的哈。如果和前面元素一样的话continue,就相当于是跳过了本层的重复元素。

代码:

def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        res = []
        path = []
        # used = len(candidates)*[False]
        def traversal(candidates,target,sum,index):
            #为了避免重复 需要对数组排序
            candidates.sort()
            if sum==target:
                res.append(path[:])
            for i in range(index,len(candidates)):
                #如果当前相加 都大于target了 那就没必要往后了
                #直接返回
                if sum + candidates[i] > target:
                    return
                    #跳过同一个树层使用过的元素
                if i > index and candidates[i] == candidates[i-1]:
                    continue
                sum +=candidates[i]
                path.append(candidates[i])
                # used[i] = True
                traversal(candidates,target,sum,i+1)
                # used[i]=False
                sum-=candidates[i]
                path.pop()
        traversal(candidates,target,0,0)
        return res 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值