代码随想录算法训练营第二十二天| 回溯1— 216. 组合总和 III,17. 电话号码的字母组合

回溯法第一天,77. 组合216. 组合总和 III17. 电话号码的字母组合。由于之前二叉树做过挺多次递归和回溯,感觉对基本做法和思想还是比较熟悉的。但是在这部分中,递归和回溯的思考更加抽象了,感觉像是在二叉树环节中,能够看着图去思考会轻松一点,但是现在这些题都需要自己去想象为一个树形,所以会更加考验抽象思考能力一些。

先贴一个回溯模板

def backtracking(path, choices):
    if 终止条件:
        保存结果 path.copy()
        return

    for choice in choices:  # 当前层的所有选择
        做选择(添加到 path)
        backtracking(path, 剩余选择)  # 递归
        撤销选择(回溯)

216. 组合总和 III

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

回溯法经典组合类型题目,与 77. 组合 类似,找出1-9中,k个能够加和为n的组合。继续使用递归三步分析。

首先是参数,参数不需要在一开始写的时候就列全,后面想到了再补也行。这道题主要是k, n, index/start(为下一层for循环搜索的起始位置), path(单个数组), res(二维数组,答案)。

然后去找终止条件,如果大于等于的话就是不需要添加开始回溯,但是其中特列是如果等于,就将目前的数组存入res。这里有一个重点,是需要存入浅拷贝的path,因为如果不这么做,加入res的path也会跟着后续回溯发生变化。

最后是单层内操作,也就是for循环内的操作,首先添加当前元素到path数组,然后开始递归,如果不能元素重复的话,记得下一次递归是要i+1,最后pop弹出最外层,也就是真正回溯的操作。然后这里有一个剪枝的操作,意思就是:你最多还需要 (k - len(path)) 个数(k为需要选取的个数),而当前数字范围是 1~9,如果从i 开始后面的数都不够用了,可以直接跳出。于是就是9-(k-len(path)) + 1,后面一个+1是range的边界问题。其实还有一种反向遍历写法会看起来简洁一点,但是后边range和递归方向会变,脑袋笨掌握好一种正序就行了(其实估计自己碰到新题的时候连剪枝都想不起来,能不超时ac就已经万幸了)。

其实对这种简单结构的递归掌握还行,上点难度判断条件多一点的递归脑子就一团浆糊了。

class Solution:
    def combinationSum3(self, k: int, n: int) -> List[List[int]]:
        res = []
        self.backtracking(k,n,1,[],res)
        return res
    
    def backtracking(self, k, n, start, path, res):
        if len(path) == k:
            if sum(path) == n:
                res.append(path.copy())
            return
        for c in range(start, 10): # 剪枝range(start, 9 - (k - len(path))+1+1)
            path.append(i)
            self.backtracking(k,n, i + 1, path, res)
            path.pop()

17. 电话号码的字母组合

17. 电话号码的字母组合 - 力扣(LeetCode)

非常有意思的一道题,一开始还想不到怎么把文字输入进去,感觉用字典会很麻烦,偷看一眼题解发现还有这种形式,学到了,用列表的索引值去对应相应的数字。然后再尝试去做,做了个大概,有些细节处理还是不到位。还是按三步走分析一下

需要的参数感觉还是差不多,还是当前数组path以及答案的二维数组result,以及index。

然后是终止条件,就是长度到达len(digits),记住用字符串的操作''.join(path)。

最后是单层递归逻辑,就是完全一样的添加,迭代,回溯三步。

class Solution:
    def __init__(self):
        self.mapping = ['','','abc','def','ghi','jkl','mno','pqrs','tuv','wxyz']

    def backtracking(self, digits, index, path, result):
        n = len(digits)
        if index == n:
            result.append(''.join(path))
            return
        letters = self.mapping[int(digits[index])]
        for c in letters:
            path.append(c)
            self.backtracking(digits, index + 1, path, result)
            path.pop()

    def letterCombinations(self, digits: str) -> List[str]:
        res = []
        if not digits:
            return []
        self.backtracking(digits, 0, [], res)
        return res

还需多练习递归的思想,感觉有时候递归+回溯确实脑袋里很难有清楚的思路,即使明白三步但也很容易卡住。相较于二叉树中的递归,这部分题目感觉更加抽象了起来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值