17.电话号码的字母组合【回溯】

本文详细介绍了如何使用回溯法解决电话号码的字母组合问题,通过建立数字与字母的映射关系,结合递归的深度优先搜索策略,动态生成所有可能的字母组合。示例中展示了对于不同长度的数字字符串,如何灵活应用回溯法。同时,文章还讨论了处理异常输入,如1*#等非数字字符的方法。
摘要由CSDN通过智能技术生成

17.电话号码的字母组合

题目链接:

力扣

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

示例:
输入:"23"
输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].

提示:

  • 0 <= digits.length <= 4
  • digits[i] 是范围 ['2', '9'] 的一个数字。

思路

从示例上来说,输入"23",最直接的想法就是两层for循环遍历了吧,正好把组合的情况都输出了。

如果输入"233"呢,那么就三层for循环,如果"2333"呢,就四层for循环......

大家应该感觉出和求组合问题遇到的一样的问题,就是这for循环的层数如何写出来,此时又是回溯法登场的时候了。

理解本题后,要解决如下三个问题:
1.数字和字母如何映射
2.两个字母就两个for循环,三个字符我就三个for循环,以此类推,然后发现代码根本写不出来
3.输入1 * #按键等等异常情况

数字和字母如何映射
可以使用map或者定义一个二位数组,例如:string numString[],来做映射,我这里定义一个二维数组,代码如下:

```
string numString[] = {
    "", // 0
    "", // 1
    "abc", // 2
    "def", // 3
    "ghi", // 4
    "jkl", // 5
    "mno", // 6
    "pqrs", // 7
    "tuv", // 8
    "wxyz", // 9
};
```

回溯法来解决n个for循环的问题:

例如:输入:"23",抽象为树形结构,如图所示:

图中可以看出遍历的深度,就是输入"23"的长度,而叶子节点就是我们要收集的结果,输出["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]。

回溯三部曲:

确定回溯函数参数
首先需要一个字符串s来收集叶子节点的结果,然后用一个字符串数组result保存起来,这两个变量我依然定义为全局。

再来看参数,参数指定是有题目中给的string digits,然后还要有一个参数就是int型的num。

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

代码如下:
```
List<String> list;
StringBuilder temp;
void backTracking(String digits, String[] numString,int num)
```

确定终止条件
例如输入用例"23",两个数字,那么根节点往下递归两层就可以了,叶子节点就是要收集的结果集。

那么终止条件就是如果num 等于 输入的数字个数(digits.length)了(本来num就是用来遍历digits的)。

然后收集结果,结束本层递归。

代码如下:
```
if (num == digits.length()) {
    list.add(temp.toString());
    return;
}
```

确定单层遍历逻辑
首先要取num指向的数字,并找到对应的字符集(手机键盘的字符集)。

然后for循环来处理这个字符集,代码如下:

```

// 取数字对应的字符集
string str= numString[digits.charAt(num) - '0'];
for (int i = 0; i < str.length(); i++) {
    temp.append(str.charAt(i));  // 处理
    backtracking(digits,numString, num + 1); // 递归,注意num+1,一下层要处理下一个数字了
    temp.deleteCharAt(temp.length()-1) // 回溯
}
```

注意:输入1 * #按键等等异常情况。

最后java代码整体如下:
class Solution {

    //设置全局列表存储最后的结果

    List<Stringlist = new ArrayList<>();

    public List<StringletterCombinations(String digits) {

        if(digits == null || digits.length() == 0){

            return list;

        }

        //初始对应所有的数字,为了直接对应2-9,新增了两个无效的字符串""

        String[] numString={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};

        //迭代处理

        backTracking(digits,numString,0);

        return list;

    }

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

    StringBuilder temp = new StringBuilder();

    //比如digits如果为"23",num 为0,则str表示2对应的 abc

    public void backTracking(String digits,String[] numString,int num){

        //遍历全部一次记录一次得到的字符串  

        if(num == digits.length()){

            list.add(temp.toString());

            return;

        }

        //str 表示当前num对应的字符串

        String str = numString[digits.charAt(num)-'0'];

        for(int i = 0;i < str.length();i++){

            temp.append(str.charAt(i));

            //c

            backTracking(digits,numString,num+1);

            //剔除末尾的继续尝试

            temp.deleteCharAt(temp.length()-1);

        }

    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值