0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何用回溯写电话号码的字母组合

算法与数据结构 来源:代码随想录 作者:程序员Carl 2021-10-29 17:06 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

17.电话号码的字母组合

力扣题目链接//leetcode-cn.com/problems/letter-combinations-of-a-phone-number/

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

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

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

说明:尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。

思路

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

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

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

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

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

数字和字母如何映射

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

conststringletterMap[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也表示树的深度。

代码如下:

vectorresult;
strings;
voidbacktracking(conststring&digits,intindex)
  • 确定终止条件

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

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

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

代码如下:

if(index==digits.size()){
result.push_back(s);
return;
}
  • 确定单层遍历逻辑

首先要取index指向的数字,并找到对应的字符集(手机键盘的字符集)。

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

intdigit=digits[index]-'0';//将index指向的数字转为int
stringletters=letterMap[digit];//取数字对应的字符集
for(inti=0;i< letters.size(); i++) {
    s.push_back(letters[i]);            //处理
backtracking(digits,index+1);//递归,注意index+1,一下层要处理下一个数字了
s.pop_back();//回溯
}

注意这里for循环,可不像是在回溯算法:求组合问题!回溯算法:求组合总和!中从startIndex开始遍历的

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

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

代码中最好考虑这些异常情况,但题目的测试数据中应该没有异常情况的数据,所以我就没有加了。

但是要知道会有这些异常,如果是现场面试中,一定要考虑到!

C++代码

关键地方都讲完了,按照关于回溯算法,你该了解这些!中的回溯法模板,不难写出如下C++代码:

//版本一
classSolution{
private:
conststringletterMap[10]={
"",//0
"",//1
"abc",//2
"def",//3
"ghi",//4
"jkl",//5
"mno",//6
"pqrs",//7
"tuv",//8
"wxyz",//9
};
public:
vector<string>result;
strings;
voidbacktracking(conststring&digits,intindex){
if(index==digits.size()){
result.push_back(s);
return;
}
intdigit=digits[index]-'0';//将index指向的数字转为int
stringletters=letterMap[digit];//取数字对应的字符集
for(inti=0;i< letters.size(); i++) {
            s.push_back(letters[i]);            //处理
backtracking(digits,index+1);//递归,注意index+1,一下层要处理下一个数字了
s.pop_back();//回溯
}
}
vector<string>letterCombinations(stringdigits){
s.clear();
result.clear();
if(digits.size()==0){
returnresult;
}
backtracking(digits,0);
returnresult;
}
};

一些写法,是把回溯的过程放在递归函数里了,例如如下代码,我可以写成这样:(注意注释中不一样的地方)

//版本二
classSolution{
private:
conststringletterMap[10]={
"",//0
"",//1
"abc",//2
"def",//3
"ghi",//4
"jkl",//5
"mno",//6
"pqrs",//7
"tuv",//8
"wxyz",//9
};
public:
vector<string>result;
voidgetCombinations(conststring&digits,intindex,conststring&s){//注意参数的不同
if(index==digits.size()){
result.push_back(s);
return;
}
intdigit=digits[index]-'0';
stringletters=letterMap[digit];
for(inti=0;i< letters.size(); i++) {
            getCombinations(digits, index + 1,s+letters[i]);//注意这里的不同
}
}
vector<string>letterCombinations(stringdigits){
result.clear();
if(digits.size()==0){
returnresult;
}
getCombinations(digits,0,"");
returnresult;

}
};

我不建议把回溯藏在递归的参数里这种写法,很不直观,我在二叉树:以为使用了递归,其实还隐藏着回溯这篇文章中也深度分析了,回溯隐藏在了哪里。

所以大家可以按照版本一来写就可以了。

总结

本篇将题目的三个要点一一列出,并重点强调了和前面讲解过的77. 组合216.组合总和III的区别,本题是多个集合求组合,所以在回溯的搜索过程中,都有一些细节需要注意的。

其实本题不算难,但也处处是细节,大家还要自己亲自动手写一写。

其他语言版本

Java

classSolution{

//设置全局列表存储最后的结果
Listlist=newArrayList<>();

publicListletterCombinations(Stringdigits){
if(digits==null||digits.length()==0){
returnlist;
}
//初始对应所有的数字,为了直接对应2-9,新增了两个无效的字符串""
String[]numString={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
//迭代处理
backTracking(digits,numString,0);
returnlist;

}

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

//比如digits如果为"23",num为0,则str表示2对应的abc
publicvoidbackTracking(Stringdigits,String[]numString,intnum){
//遍历全部一次记录一次得到的字符串
if(num==digits.length()){
list.add(temp.toString());
return;
}
//str表示当前num对应的字符串
Stringstr=numString[digits.charAt(num)-'0'];
for(inti=0;i< str.length(); i++) {
            temp.append(str.charAt(i));
            //c
backTracking(digits,numString,num+1);
//剔除末尾的继续尝试
temp.deleteCharAt(temp.length()-1);
}
}
}

Python

classSolution:
ans=[]
s=''
letterMap={
'2':'abc',
'3':'def',
'4':'ghi',
'5':'jkl',
'6':'mno',
'7':'pqrs',
'8':'tuv',
'9':'wxyz'
}

defletterCombinations(self,digits):
self.ans.clear()
ifdigits=='':
returnself.ans
self.backtracking(digits,0)
returnself.ans

defbacktracking(self,digits,index):
ifindex==len(digits):
self.ans.append(self.s)
return
else:
letters=self.letterMap[digits[index]]#取出数字对应的字符集
forletterinletters:
self.s=self.s+letter#处理
self.backtracking(digits,index+1)
self.s=self.s[:-1]#回溯

python3

classSolution:
defletterCombinations(self,digits:str)->List[str]:
res=[]
s=""
letterMap=["","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"]
ifnotlen(digits):returnres
defbacktrack(digits,index,s):
ifindex==len(digits):
returnres.append(s)
digit=int(digits[index])#将index指向的数字转为int
letters=letterMap[digit]#取数字对应的字符集
foriinrange(len(letters)):
s+=letters[i]
backtrack(digits,index+1,s)#递归,注意index+1,一下层要处理下一个数字
s=s[:-1]#回溯
backtrack(digits,0,s)
returnres

责任编辑:haq
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 编程
    +关注

    关注

    90

    文章

    3707

    浏览量

    96765
  • 代码
    +关注

    关注

    30

    文章

    4941

    浏览量

    73148

原文标题:电话号码的字母组合!

文章出处:【微信号:TheAlgorithm,微信公众号:算法与数据结构】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    常用电子元器件字母和含义解析

    在电子技术领域中,电子元器件是构成各种电子设备的基础。而为了在电路图、元器件清单、PCB设计等环节中快速识别和管理这些元器件,工程师们采用了一套标准的字母或符号标识系统。 一、电阻(R) 含义 字母
    的头像 发表于 12-05 13:45 85次阅读

    元服务发布配置开发者服务信息

    ://或https://开头的合法URL。此选项仅支持中国大陆企业/个人开发者、海外企业开发者的应用类元服务。 客服电话号码:请使用“国际区号/国内区号-电话号码”的格式,如
    发表于 10-31 17:58

    5.5v法拉电容 后面字母代表什么意思

    文章解析了法拉电容型号中字母后缀的含义,涵盖应用场景、介质材料、封装形式等,揭示其技术参数与性能特点。
    的头像 发表于 09-17 09:15 485次阅读
    5.5v法拉电容 后面<b class='flag-5'>字母</b>代表什么意思

    如何制作字母数字键盘?

    制作字母数字键盘
    发表于 09-05 07:24

    生产线回溯追溯系统选型:中设智控方案如何破解行业痛点?

    中设智控产线回溯追溯方案,从硬件到功能,精准破解行业痛点,为电子制造、新能源等行业提供高效、可靠的生产管理工具,助力企业实现智能化生产升级,值得选型参考。
    的头像 发表于 07-18 11:19 708次阅读
    生产线<b class='flag-5'>回溯</b>追溯系统选型:中设智控方案如何破解行业痛点?

    单模光缆型号字母代码及其含义

    单模光缆的型号字母代码主要用于标识光缆的分类、结构、护层及光纤类型等关键信息,以下是一些常见的单模光缆型号字母代码及其含义: 一、光缆分类代码 GY:通信用室外光缆,这是最常见的室外光缆分类代码
    的头像 发表于 07-17 10:27 2424次阅读

    组合导航系统如何用单天线实现低成本?

    在自动驾驶、无人机飞行和航空导航等领域,高精度、高可靠性的定位与姿态测量至关重要,但传统方案往往因双天线设计或高成本IMU而难以普及。ER-GNSS/MINS-07组合导航系统突破这一瓶颈,以单天线
    的头像 发表于 07-04 15:05 431次阅读
    <b class='flag-5'>组合</b>导航系统如<b class='flag-5'>何用</b>单天线实现低成本?

    山东LP-SCADA故障回溯功能的好处

    关键字:LP-SCADA, LP-SCADA平台 , LP-SCADA系统, 软件回溯功能,蓝鹏测控 得益于本平台毫秒级的采集延迟,本平台除了具有普通监控采集平台的所有监控功能外,还可用于产线、设备
    发表于 05-29 14:42

    答疑|3D打印能打印立体字母吗?

    最近有朋友留言问:3D打印能打印那种立体字母吗?会不会很难实现? JLC3D小编来解答:当然可以!无论是单独的字母,还是组合成单词或句子,3D打印都可以实现的。 以下是一些关于打印立体字母
    发表于 05-21 16:17

    旺诠合金电阻的命名规则

    (Ω)为单位。在旺诠合金电阻的命名中,电阻值通常通过数字或字母组合来表示。例如,“100”可能表示100欧姆的电阻值,而“K”则通常表示千欧姆(kΩ)。 二、精度 精度表示电阻值的准确度,通常以百分比来表示。旺诠合金电阻的精度等级通
    的头像 发表于 05-20 11:22 476次阅读
    旺诠合金电阻的命名规则

    阻燃耐火电线型号字母归纳

    阻燃耐火电线的型号字母表示通常涉及阻燃和耐火特性的标识,以下是对这些字母的详细归纳: 阻燃特性标识 ZR:这是最常见的阻燃电线标识,表示电线具有阻燃特性。例如,ZR-YJV表示阻燃铜芯聚氯乙烯绝缘
    的头像 发表于 05-09 10:31 6972次阅读

    防火双绞线是什么字母

    防火双绞线的标识字母主要取决于其符合的防火标准或认证体系,常见的标识方式如下: 1. 国际通用标准(如UL认证) CMP/CMR/CM: CMP(Plenum):最高阻燃等级,适用于通风管道或空气
    的头像 发表于 04-03 09:49 836次阅读

    AN-737: 如何用ADIsimADC完成ADC建模

    电子发烧友网站提供《AN-737: 如何用ADIsimADC完成ADC建模.pdf》资料免费下载
    发表于 01-13 14:54 1次下载
    AN-737: 如<b class='flag-5'>何用</b>ADIsimADC完成ADC建模

    村田电容标签材质代码如何看?

    字母组合代表了电容的基本类型和用途。例如,GRM表示一般用途片状多层陶瓷电容器。 二、解读尺寸代码 在型号之后,通常会有一串数字或字母数字组合,用以表示电容的尺寸。例如,18、0603等,这些数字或代码对应了电容的长和宽。具体的
    的头像 发表于 01-13 14:14 1426次阅读

    HarmonyOS NEXT 原生应用开发:社交通讯录界面实现

    一、案例想法 本DEMO展示了如何在HarmonyOS NEXT平台上,使用ArkTS开发语言构建一个简单的社交通讯录界面。用户可以在此界面上浏览联系人列表,每个联系人条目包含姓名、电话号码以及一个
    发表于 01-09 14:37