回溯:216. 组合总和 III、17. 电话号码的字母组合

文章讲述了在编程题目中,如何使用回溯法解决组合总和III和电话号码的字母组合问题,涉及递归、终止条件的设定、剪枝技巧以及代码实现。作者分享了解题思路和遇到的问题,强调了回溯法在多集合组合问题中的重要性。
摘要由CSDN通过智能技术生成

提示:努力生活,开心、快乐的一天


216. 组合总和 III

题目链接:216. 组合总和 III

💡解题思路

  1. 与之前组合题相似,只是此次集合变成固定的啦[1,9]
    在这里插入图片描述
  2. 回溯三部曲:
    和之前组合的题一样,先定义两个全局变量:result:存放结果集;path:符合条件的结果
  • 确定递归函数参数:参数不用一上来直接确定好,可以在后面的代码编写中,缺什么再补,
    已经确定的参数有:1、targetSum(int)目标和,也就是题目中的n。2、k(int)就是题目中要求k个数的集合。3、sum(int)为已经收集的元素的总和,也就是path里元素的总。4、startIndex(int)为下一层for循环搜索的起始位置。
let result = []
    let path = []
    let sum = 0
    //startIndex :for循环遍历的起始位置
    const dfs = (targetSum,k,sum,startIndex) => {
  • 确定终止条件:k其实就已经限制树的深度,因为就取k个元素,树再往下深了没有意义,所以如果path.size() 和 k相等了,就终止。如果此时path里收集到的元素和(sum) 和targetSum(就是题目描述的n)相同了,就用result收集当前的结果。
if (path.length===k && sum === n) {
            result.push([...path])
            return
        }
  • 单层搜索过程:for循环+递归+回溯。集合固定的就是9个数[1,…,9],所以for循环固定i<=9,处理过程就是 path收集每次选取的元素,相当于树型结构里的边,sum来统计path里元素的总和。处理过程 和 回溯过程是一一对应的,处理有加,回溯就要有减
for (let i = startIndex; i <= 9 ; i++){
            sum += i //path里元素的总和
            path.push(i)//收集选取的元素
            dfs(i + 1)//递归,深一层
            sum -= i//回溯
            path.pop()//回溯
        }

🤔遇到的问题

  1. 终止条件遗漏啦。终止条件有2个:1、当前集合的个数=k;2、当前集合的和=n
  2. for循环时,遍历的集合区间是左闭右闭,所以,i<=9

💻代码实现

回溯-包含剪枝

var combinationSum3 = function(k, n) {
    let result = []
    let path = []
    let sum = 0
    //startIndex :for循环遍历的起始位置
    const dfs = (startIndex) => {
        // 剪枝操作
        if (sum > n) return
        //终止条件有2个:1、当前集合的个数=k;2、当前集合的和=n
        if (path.length===k && sum === n) {
            result.push([...path])
            return
        }
        for (let i = startIndex; i <= 9 - (k - path.length) + 1; i++){
            sum += i //path里元素的总和
            path.push(i)//收集选取的元素
            dfs(i + 1)//递归,深一层
            sum -= i//回溯
            path.pop()//回溯
        }
    }
    dfs(1)
    return result
};

🎯题目总结

本题有2个地方可以做剪枝:
1、已选元素总和如果已经大于n了,那么往后遍历就没有意义了,直接剪掉,那么剪枝的地方可以放在递归函数开始的地方,剪枝代码如下:

 if (sum > n) return

2、 for循环的范围也可以剪枝,i <= 9 - (k - path.size()) + 1就可以了
在这里插入图片描述

17. 电话号码的字母组合

题目链接:17. 电话号码的字母组合

💡解题思路

  1. 要解决如下三个问题:
    问题一:数字和字母如何映射
    问题二:两个字母就两个for循环,三个字符我就三个for循环,以此类推,然后发现代码根本写不出来
    问题三:输入1 * #按键等等异常情况
  2. 解决上面问题:
    问题一的解决:定义一个数组,const map = [“”, “”, “abc”, “def”, “ghi”, “jkl”, “mno”, “pqrs”, “tuv”, “wxyz”];
    问题二的解决:回溯法来解决n个for循环的问题
    问题三的解决:题目的测试数据中应该没有异常情况的数据,如果是现场面试中,一定要考虑到!
  3. 回溯三部曲:
  • 确定回溯函数参数:定义两个全局变量,result保存结果集,str收集叶子节点的结果。参数指定是有题目中给的digits,然后还要有一个参数就是index,index是记录遍历第几个数字了,就是用来遍历digits的(题目中给出数字字符串),同时index也表示树的深度
  • 确定终止条件:终止条件就是如果index 等于 输入的数字个数(digits.size)了(本来index就是用来遍历digits的),然后收集结果,结束本层递归。
  • 确定单层遍历逻辑:首先要取index指向的数字,并找到对应的字符集,然后for循环来处理这个字符集

🤔遇到的问题

  1. 输入的字符串为空获知只有一个数字的特殊操作可以单独写

💻代码实现

回溯

var letterCombinations = function (digits) {
    let result = []// 存放符合条件结果的集合
    let str = []// 用来存放符合条件结果
    //字符串中数字与字母的对应map
    const map = ["", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"];
    //字符串的长度为空
    if (!digits.length) return []
    //字符串的长度为1
    if (digits.length === 1) return map[digits].split('')
    //index:字符串的下标,记录遍历第几个数字,也表示树的深度。
    const backtracking = (digits, index) => {
        //终止条件:index 等于 输入的数字个数(digits.size)了,收集结果,结束本层递归
        if (index === digits.length) {
            result.push(str.join(''))
            return
        }
        //要取index指向的数字,并找到对应的字符集
        //然后for循环来处理这个字符集
        for (const item of map[digits[index]]) {
            str.push(item)// 处理
            backtracking(digits, index + 1) // 递归,注意index+1,一下层要处理下一个数字了
            str.pop()// 回溯
        }
    }
    backtracking(digits, 0)
    return result
};

🎯题目总结

多个集合求组合,需要画图,确定集合的宽度及树的深度,也就是for循环的条件和遍历的深度
在这里插入图片描述

🎈今日心得

电话号码的题确实不容易想到

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值