LeetCode刷题笔记:17.电话号码的字母组合

1. 问题描述

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
2: “abc”,
3: “def”,
4: “ghi”,
5: “jkl”,
6: “mno”,
7: “pqrs”,
8: “tuv”,
9: “wxyz”

2. 解题思路

核心思想:回溯
画出树形图(以输入digits=”23“为例):

----------------------for循环,横向遍历-------------------->
|                数字 2 对应的集合[abc]中取字母
|                      /       |        \
|                  取字母a   取字母b    取字母c
|                  /           |           \
|数字3对应的集合[def]中取字母  集合[def]中取字母  集合[def]中取字母
|           / | \            / | \            / | \ 
递归,   取d  取e  取f     取d  取e  取f     取d  取e  取f
纵向
遍历     /     |    \     /     |    \     /     |    \
|
|    [ad]   [ae]  [af] [bd]  [be]   [bf] [cd]  [ce]  [cf]
|
|
v                 

⭐由上图可知:
①遍历的深度即输入字符串 digits 的长度
②所有叶子节点即最终的结果集

⭐需要定义那些全局变量?
①一个字符串数组 res,用来存放最终的结果集
②一个临时字符串 temp,暂存叶子节点的结果

⭐设计的回溯函数需要哪些参数?
①题目给定的 String digits
②数字到对应字母集合的映射,可定义为一个String[ ] num2String
③记录当前遍历到第几个数字的遍历num,也表示树的深度

⭐递归终止条件:
当前树的深度(即 num)等于输入字符串 digits 的长度
例如当前输入 digits 为"23",则需要从根节点向下递归两层即可。

3. 代码实现

class Solution {
	// res 存放最终组合结果
	List<String> res = new ArrayList<>();
	public List<String> letterCombinations(String digits) {
		// 判空
		// 如果 digits 为 null,则 digits.length() 就会报空指针异常。所以这里先判断是否为空,再调用函数
		if (digits == null || digits.length() == 0){
			return res;
		}
		// 建立 数字 ---> 字母集合 的映射,数组下标直接对应数字 2 ~ 9
		String[] num2String = {"", "", "abc", "def", "ghi", "jkl", "mno", pqrs, "tuv", "wxyz"};
		// 迭代
		backTracking(digits, num2String, 0);
		return res;
	}

	// 由于每次迭代都会获取一个字符串,选择可变且更为高效的StringBuilder类
	StringBuilder tmp = new StringBuilder();
	
	// 参数 String digits:输入的字符串,例如'23'
	// 参数 String[] num2String:数字 ---> 字母集合的映射
	// 参数 num:树的深度,也表示输入的 digits 中包含的数字的个数,记录当前遍历到第几个数字	
	private void backTracking(String digits, String[] num2String, int num){
		// 递归终止条件:num 等于输入的数字个数
		if (num == digits.length()){
			res.add(temp.toString());
			return;
		}
		// str 记录当前遍历的数字对应的字母集合
		// 例如:若 digits = '23', num = 0
		//      则 str 表示输入字符串 digits 的第一个字符'2'所对应的字母集合"abc"
		// digits.charAt(num)得到一个字符,该字符与字符'0'相减,实际上是是两个字符的ASCII码相减,返回就是int
		String str = num2String[digits.charAt(num) - '0'];
		// 遍历 str 所表示的字母集合
		for (int i = 0; i < str.length(); i++) {
			temp.append(str.charAt(i));
			// 递归,将 num 改为num + 1,即处理下一个数字
			backTracking(digits, num2String, num + 1);
			// 回溯,删除末尾字符,继续尝试
			temp.deleteCharAt(temp.length - 1)
		}
	}
}

再写一种实现:

class Solution {

    // 映射:数字 ---> 号码
    private String[] num2LetterSet = {"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};

    // 路径
    private StringBuilder path = new StringBuilder();

    // 结果集
    private List<String> res = new ArrayList<>();

    public List<String> letterCombinations(String digits) {
        if(digits == null || digits.length() == 0) {
        	return res;
        }
        backTracking(digits,0);
        return res;
    }

    // 回溯函数
    private void backTracking(String digits, int index) {
        if(path.length() == digits.length()) {
            res.add(path.toString());
            return;
        }
        // 当前数字对应的字母集合
        String letterSet = num2LetterSet[digits.charAt(index)-'2'];
        // 将字符串形式的字母集合转为字符数组并遍历
        for(char ch: letterSet.toCharArray()) {
            path.append(ch);
            backTracking(digits, index + 1);
            path.deleteCharAt(path.length() - 1);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值