代码随想录算法训练营第25天 | 216、17

文章讲述了如何利用回溯法解决寻找数字组合的问题,例如找出所有和为n的k个数的组合,每个数字1到9最多使用一次。示例展示了不同输入下的输出结果,并解析了解题思路,包括回溯法的实现细节和跳出条件。此外,还介绍了电话号码字母组合的问题,同样运用回溯法处理多对一映射的组合问题。

216.组合总和Ⅲ

题目描述

找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:
只使用数字1到9
每个数字 最多使用一次
返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。
示例1:
输入:k=3,n=7k = 3, n = 7k=3,n=7
输出:[[1,2,4]][[1,2,4]][[1,2,4]]
示例2:
输入:k=3,n=9k = 3, n = 9k=3,n=9
输出:[[1,2,6],[1,3,5],[2,3,4]][[1,2,6], [1,3,5], [2,3,4]][[1,2,6],[1,3,5],[2,3,4]]
示例3:
输入:k=4,n=1k = 4, n = 1k=4,n=1
输出:[][][]

思路

组合问题首先想到的肯定是回溯法,但是如何使用就需要我们捕捉一些关键字了。
1、只使用数字1-9,说明回溯循环时只需遍历1-9即可
2、每个数字最多使用一次,说明在回溯循环时每次遍历需要从startindex开始
读懂关键字之后可以套入回溯法的常规套路:
1、回溯方法中的跳出条件为:数字达到了k个数的时候即可跳出,因为此时不符合条件则之后也不可能符合条件了,可以直接跳出。同时,若几个数字的和已经超出了所需条件,那么因为使用的是数字1-9,所以之后也不可能再减小,可以直接跳出。
2、答案列表添加的条件:数量上符合k个数字,同时几个数字的和符合条件,即可添加。

题解

class Solution {
    LinkedList<Integer> path = new LinkedList<>();
    List<List<Integer>> result = new ArrayList<>(); 
    public List<List<Integer>> combinationSum3(int k, int n) {
        helper(n,k,1,0);
        return result;
    }
    public void helper(int targetSum,int k,int startIndex,int sum){
        if(sum > targetSum){
            return ;
        }
        if(path.size() == k){
            if(sum == targetSum){
                result.add(new ArrayList<>(path));
            }
            return;
        }
        for(int i = startIndex;i<= 9-(k-path.size())+1;i++){
            path.add(i);
            sum += i;
            helper(targetSum,k,i+1,sum);
            path.removeLast();
            sum -= i;
        }
    }
}

总结

本题是组合问题的一个应用,能够帮助熟悉回溯问题中组合问题的套路。

17.电话号码的字母组合

题目描述

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射与电话按键相同。注意 1 不对应任何字母。
示例1:
输入:digits="23"digits = "23"digits="23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]["ad","ae","af","bd","be","bf","cd","ce","cf"]["ad","ae","af","bd","be","bf","cd","ce","cf"]
示例2:
输入:digits=""digits = ""digits=""
输出:[][][]
示例3:
输入:digits="2"digits = "2"digits="2"
输出:["a","b","c"]["a","b","c"]["a","b","c"]

思路

首先,能看出本题也是一个对回溯组合的应用,但本题存在一些难点:
1、从数字到字母的映射关系和遍历时一个数字对应了多个字母,需要考虑
2、本题中返回的数组是字符串类型,那么可以考虑使用char数组或StringBuilder来进行拼接
3、要求得到的结果是不区分顺序的,即,ab和ba表示的是同一个组合,所以在回溯的循环中还是要每次从startindex开始。

题解

class Solution {
    List<String> list = new ArrayList<>();
    public List<String> letterCombinations(String digits) {
        if(digits == null || digits.length() == 0){
            return list;
        }
        String[] numString = {"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
        helper(digits,numString,0);
        return list;
    }
    StringBuilder tmp = new StringBuilder();
    public void helper(String digits,String[] numString,int num){
        if(num == digits.length()){
            list.add(tmp.toString());
            return;
        }
        String string = numString[digits.charAt(num)-'0'];
        for(int i=0;i<string.length();i++){
            tmp.append(string.charAt(i));
            helper(digits,numString,num+1);
            tmp.deleteCharAt(tmp.length()-1);
        }
    }
}

总结

本题即使进行了拆解之后还是很难的,要注意在回溯的过程中生成的字符串要及时更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值