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

216.组合总和III 

如果把 组合问题理解了,本题就容易一些了。 

题目链接/文章讲解:代码随想录

视频讲解:和组合问题有啥区别?回溯算法如何剪枝?| LeetCode:216.组合总和III_哔哩哔哩_bilibili

相对于77. 组合 (opens new window),无非就是多了一个限制,本题是要找到和为n的k个数的组合,而整个集合已经是固定的了[1,...,9]。

已选元素总和如果已经大于n(图中数值为4)了,那么往后遍历就没有意义了,直接剪掉。

for循环的范围也可以剪枝,i <= 9 - (k - path.size()) + 1就可以了。

当前递归中,组合中目前已经有path.size()个元素,题目要求有k个,

还需要/还缺:k-path.size()个元素

i控制的是取每个组合的每个集合里的起始位置

i至多只能到9-(k-path.size()),才能满足后面的元素,足够填补上空缺的元素

9-(k-path.size())+1:下标补齐

class Solution {
    List<List<Integer>> result = new ArrayList<>();// 存放结果集
    List<Integer> path = new ArrayList<>();// 符合条件的结果

    public List<List<Integer>> combinationSum3(int k, int n) {
        trackbacking(k, n, 1, 0);
        return result;
    }

    // targetSum:目标和,也就是题目中的n。
    // k:题目中要求k个数的集合。
    // sum:已经收集的元素的总和,也就是path里元素的总和。
    // startIndex:下一层for循环搜索的起始位置。
    public void trackbacking(int k, int n, int startIndex, int sum){
        if(sum > n) return; // 剪枝操作,已选元素总和如果已经大于n了,那么往后遍历就没有意义了,直接剪掉

        if(path.size() == k){
            if(sum == n) result.add(new ArrayList<>(path));
            return;// 如果path.size() == k 但sum != targetSum 直接返回
        }

        for(int i = startIndex; i <= 9 - (k - path.size()) + 1; i++){//for循环的范围也可以剪枝
            sum += i;
            path.add(i);
            trackbacking(k, n, i + 1, sum);// 注意i+1调整startIndex
            sum -= i;// 回溯
            path.remove(Integer.valueOf(i));// 回溯
        }
    }
}

17.电话号码的字母组合 

本题大家刚开始做会有点难度,先自己思考20min,没思路就直接看题解。 

题目链接/文章讲解:代码随想录

视频讲解:还得用回溯算法!| LeetCode:17.电话号码的字母组合_哔哩哔哩_bilibili

本题是两个集合里的元素做组合,就不需要startIndex来帮忙控制,集合里我们之前遍历过哪些元素。

index是记录遍历第几个数字了,就是用来遍历digits的(题目中给出数字字符串),同时index也表示树的深度。

叶子节点就是要收集的结果集。

那么终止条件就是如果index 等于 输入的数字个数(digits.size)了(本来index就是用来遍历digits的)。然后收集结果,结束本层递归。

class Solution {
    //设置全局列表存储最后的结果
    List<String> result = new ArrayList<>();

    //每次迭代获取一个字符串,所以会设计大量的字符串拼接,所以这里选择更为高效的 StringBuild
    StringBuilder path = new StringBuilder();

    //初始对应所有的数字,为了直接对应2-9,新增了两个无效的字符串""
    String[] letterMap = {
        "", // 0
        "", // 1
        "abc", // 2
        "def", // 3
        "ghi", // 4
        "jkl", // 5
        "mno", // 6
        "pqrs", // 7
        "tuv", // 8
        "wxyz", // 9
    };

    public List<String> letterCombinations(String digits) {
        if(digits == null || digits.length() == 0) return result;
        //迭代处理
        trackingback(digits, 0);
        return result;
    }

    //比如digits如果为"23",num 为0,则str表示2对应的 abc
    public void trackingback(String digits, int index){
        //遍历全部一次记录一次得到的字符串
        if(digits.length() == index){
            result.add(path.toString());
            return;
        }

        //str 表示当前num对应的字符串
        int digit = digits.charAt(index) - '0';// 将index指向的数字转为int
        String letter = letterMap[digit];// 取数字对应的字符集

        for(int i = 0; i < letter.length(); i++){
            path.append(letter.charAt(i));// 处理
            trackingback(digits, index + 1);// 递归,注意index+1,一下层要处理下一个数字了
            path.delete(path.length() - 1, path.length());// 回溯,剔除末尾的继续尝试
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值