一刷72-回溯算法-17电话号码的字母组合(m)

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

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

在这里插入图片描述

输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
说明:尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。

输入:digits = ""
输出:[]

输入:digits = "2"
输出:["a","b","c"]
------------------------------
思考:
从示例上来说,输入"23",最直接的想法就是两层for循环遍历了吧,正好把组合的情况都输出了。

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

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

理解本题后,要解决如下三个问题:

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

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

const string letterMap[10] = {
    "", // 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型的index。

注意这个index可不是 77.组合 和216.组合总和III 中的startIndex了。

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

vector<string> result;
string s;
void backtracking(const string& digits, int index)
确定终止条件
例如输入用例"23",两个数字,那么根节点往下递归两层就可以了,叶子节点就是要收集的结果集。

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

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

代码如下:

if (index == digits.size()) {
    result.push_back(s);
    return;
}
确定单层遍历逻辑
首先要取index指向的数字,并找到对应的字符集(手机键盘的字符集)。

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

int digit = digits[index] - '0';        // 将index指向的数字转为int
string letters = letterMap[digit];      // 取数字对应的字符集
for (int i = 0; i < letters.size(); i++) {
    s.push_back(letters[i]);            // 处理
    backtracking(digits, index + 1);    // 递归,注意index+1,一下层要处理下一个数字了
    s.pop_back();                       // 回溯
}
注意这里for循环,可不像是在回溯算法:求组合问题! (opens new window)和回溯算法:求组合总和!
中从startIndex开始遍历的。

因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而77. 组合和
216.组合总和III 都是是求同一个集合中的组合!

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

代码中最好考虑这些异常情况,但题目的测试数据中应该没有异常情况的数据,所以我就没有加了。
但是要知道会有这些异常,如果是现场面试中,一定要考虑到!
-------------------------
代码:
class Solution{
	List<String> res = new ArrayList<>();//设置全局列表存储最后的结果s: 结果集
    StringBuilder temp = new StringBuilder(); 
	public List<String> letterCombinations(String digits){
		if(digits==null || digits.length()==0) return new ArrayList<>();//特判
		 String[] numString={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
		 backTracking(digits,numString,0);
		 return res; //初始对应所有的数字,为了直接对应2-9,新增了两个无效的字符串""
	}
	 public void backTracking(String digits,String[] numString,int num){
		if(num==digits.length()){//递归结束条件
			res.add(temp.toString());//遍历全部一次记录一次得到的字符串
			return;
		}	
		String str = numString[digits.charAt(num)-'0']; //str 表示当前num对应的字符串
		for(int i = 0;i < str.length();i++){
			temp.append(str.charAt(i));
			backTracking(digits,numString,num+1);
			temp.deleteCharAt(temp.length()-1);//剔除末尾的继续尝试
		}
	}
}
//每次迭代获取一个字符串,所以会设计大量的字符串拼接,所以这里选择更为高效的 StringBuild
//比如digits如果为"23",num 为0,则str表示2对应的 abc
//num : 用来遍历digits

力扣链接

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值