算法训练Day25 | LeetCode216. 组合总和III(和77.组合很像!);LeetCode17. 电话号码的字母组合(不同集合中组合)

目录

LeetCode216. 组合总和III

1. 思路

2. 代码实现

3. 剪枝

4. 复杂度分析

5. 思考与收获

LeetCode17. 电话号码的字母组合

1. 思路

2. 代码实现

3. 复杂度分析

4. 思考与收获


LeetCode216. 组合总和III

链接:  216. 组合总和 III - 力扣(LeetCode)

1. 思路

本题就是在[1,2,3,4,5,6,7,8,9]这个集合中找到和为n的k个数的组合。

暴力思路

最开始想到的就是嵌套K个for循环,比如说K=3 ,就嵌套三个for循环找,但是这里我们并没有确定K到底是多少,K也是一个变量,这时候我们想到回溯算法,用递归来控制嵌套几层for循环。

回溯算法思路

相对于 77. 组合 无非就是多了一个限制,本题是要找到和为n的k个数的组合,而整个集合已经是固定的了[1,...,9]。想到这一点了,做过 77.组合 之后,本题是简单一些了。

本题k相当于了树的深度,9(因为整个集合就是9个数)就是树的宽度。例如 k = 2,n = 4的话,就是在集合[1,2,3,4,5,6,7,8,9]中求 k(个数) = 2, n(和) = 4的组合。选取过程如图:图中,可以看出,只有最后取到集合(1,3)和为4 符合条件;

注意:取2 的时候,剩下的在[ 3…9 ] 中取,为什么不包括1? 因为组合问题不强调元素的顺序,21和12是同一个组合,为了避免重复,不包括1;那为什么也不包括2? 因为组合中每个元素只可以用一次;

2. 代码实现

回溯三部曲

2.1 确定递归函数参数

依然需要一维数组path来存放符合条件的结果,二维数组result来存放结果集;这里我依然定义path 和 result为全局变量。至于为什么取名为path?从上面树形结构中,可以看出,结果其实就是一条根节点到叶子节点的路径。

接下来还需要如下参数:

  • targetSum(int)目标和,也就是题目中的n。
  • k(int)就是题目中要求k个数的集合。
  • sum(int)为已经收集的元素的总和,也就是path里元素的总和。
  • startIndex(int)为下一层for循环搜索的起始位置。
class Solution:
    def __init__(self):
        self.res = []
        self.sum_now = 0
        self.path = []
		def combinationSum3(self, k: int, n: int) -> [[int]]:
        self.backtracking(k, n, 1)
        return self.res

    def backtracking(self, k: int, n: int, start_num: int):

优化:

  1. 其实这里sum这个参数也可以省略

    每次targetSum减去选取的元素数值,然后判断如果targetSum为0了,说明收集到符合条件的结果了,我这里为了直观便于理解,还是加一个sum参数;

  2. 还要强调一下,回溯法中递归函数参数很难一次性确定下来,一般先写逻辑,需要啥参数了,填什么参数;

2.2 确定终止条件

什么时候终止呢?

在上面已经说了,k其实就已经限制树的深度,因为就取k个元素,树再往下深了没有意义。所以如果path.size() 和 k相等了,就终止。

什么时候收集结果集呢?

如果此时path里收集到的元素和(sum) 和targetSum(就是题目描述的n)相同了,就用result收集当前的结果。

if len(self.path) == k:  # len(path)==k时不管sum是否等于n都会返回
    if self.sum_now == n:
        self.res.append(self.path[:])
    return

2.3 单层搜索过程

本题和77.组合区别之一就是集合固定的就是9个数,[1…9],所以for循环固定i≤9;

处理过程就是 path收集每次选取的元素,相当于树型结构里的边,sum来统计path里元素的总和;

for i in range(start_num, 10):
    self.path.append(i)
    self.sum_now += i
    self.backtracking(k, n, **i + 1**)
    self.path.pop()
    self.sum_now -= i

别忘了处理过程 和 回溯过程是一一对应的,处理有加,回溯就要有减!

为什么下一层递归要取i+1,之前有解释过!!

为什么不取1,为什么不取i? 再粘贴过来一次~

注意:取2 的时候&#

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值