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

216.组合总和III

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

文档讲解:代码随想录/组合总和III

视频讲解:视频讲解-组合总和III

状态:已完成(1遍)

解题过程 

看到题目的第一想法

 运用回溯的思维,首先确定终止条件,也就是当前小数组长度等于k,再对当前和sum进行判断,是否为n,如果为n,则ans记录当前小数组,再return;随后用for循环,i=每一层递归的startIndex,在每一层for循环中对小数组和当前sum值进行更新,递归结束之后对sum和小数组进行回溯。这道题如何进行剪枝,我没有想法,想不出来。

手搓代码如下:

/**
 * @param {number} k
 * @param {number} n
 * @return {number[][]}
 */
var combinationSum3 = function(k, n) {
    let ans = [],smallArr = [];
    // let sum = 0;
    const sumThree = function(startIndex,sum){
        if(smallArr.length == k){
            //如果数组到达k个
            if(sum == n){
                ans.push(smallArr.slice());
            }
            return;
        }
        for(let i = startIndex;i<=9;i++){
            smallArr.push(i);
            sum += i;
            sumThree(i+1,sum);
            sum -= i;
            smallArr.pop();
        }
    }
    sumThree(1,0);
    return ans;
};

提交没有问题,令人意外的是运行时间还不算靠后。

看完代码随想录之后的想法 

大体思路没有什么区别!不过剪枝这块倒是学到了,直接在最开始进行一个sum的判断就可以。

讲解代码如下:

/**
 * @param {number} k
 * @param {number} n
 * @return {number[][]}
 */
var combinationSum3 = function(k, n) {
    let res = [];
    let path = [];
    let sum = 0;
    const dfs = (path,index) => {
        // 剪枝操作
        if (sum > n){
            return
        }
        if (path.length == k) {
            if(sum == n){
                res.push([...path]);
                return
            }
        }
        for (let i = index; i <= 9 - (k-path.length) + 1;i++) {
            path.push(i);
            sum = sum + i;
            index += 1;
            dfs(path,index);
            sum -= i
            path.pop()
        }
    }
    dfs(path,1);
    return res
};

总结

其实这种剪枝我觉得也可以这样写:

/**
 * @param {number} k
 * @param {number} n
 * @return {number[][]}
 */
var combinationSum3 = function (k, n) {
    let ans = [], smallArr = [];
    // let sum = 0;
    const sumThree = function (startIndex, sum) {
        if (smallArr.length == k) {
            //如果数组到达k个
            if (sum == n) {
                ans.push(smallArr.slice());
            }
            return;
        }
        for (let i = startIndex; i <= 9; i++) {
            smallArr.push(i);
            sum += i;
            // 和的剪枝
            if (sum > n) {
                sum -= i;
                smallArr.pop();
                break;
            }
            sumThree(i + 1, sum);
            sum -= i;
            smallArr.pop();
        }
    }
    sumThree(1, 0);
    return ans;
};

提交也是没有问题的。 


 17.电话号码的字母组合

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

文档讲解:代码随想录/电话号码的字母组合

视频讲解:视频讲解-电话号码的字母组合

状态:已完成(1遍)

解题过程  

看到题目的第一想法

我能确定的部分是这个N叉树的深度是digits的长度;终止条件就是当前小字符串的长度等于digits的长度。但我想不出来如何建立一个数字和字母对应的关系,也想不出来每次for循环开始时,如何确定从什么字母开始遍历,遍历多少个(7和9对应的字母数量是4个。和别的数字不一样)。

 看完代码随想录之后的想法 

用了一个数组来创建数字和字母对应关系,再用map[n[a]]来确定每次for循环遍历的那几个字母。

/**
 * @param {string} digits
 * @return {string[]}
 */
var letterCombinations = function(digits) {
    const k = digits.length;
    const map = ["","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"];//创建数字和字母的对应关系
    if(!k) return [];
    if(k === 1) return map[digits].split("");

    const res = [], path = [];
    backtracking(digits, k, 0);
    return res;

    function backtracking(n, k, a) {
        if(path.length === k) {
            res.push(path.join(""));//长度相等,push进结果数组
            return;
        }
        for(const v of map[n[a]]) {
            path.push(v);
            backtracking(n, k, a + 1);
            path.pop();
        }
    }
};

 

总结

这道题难点感觉还是不太容易能想到,希望二刷的时候可以记起来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值