leetcode17 电话号码的字母组合
方法1 if-else方法
if-else方法的思路及其简单粗暴,如下图所示,以数字234为例,数字2所对应的字母是abc,数字3所对应的是def,数字4所对应的是ghi,最后所产生的结果就类似于我们中学所学过的树状图一样,从左到右的一组一组生成结果,首先取出数字2的第一个索引对应的a,然后紧接着添加数字3对应的第一个索引的字母d,然后再添加数字4所对应的ghi,分别组成adg、adh、adi,然后一直进行排列组合,直到把所有的结果都列举完,那么就程序就执行完了。

python完整代码:
class Solution:def letterCombinations(self, digits):# 获取输入数字串的长度n = len(digits)result = []  # 用于存储最终的字母组合结果if n == 0:return result  # 如果输入为空字符串,则直接返回空列表for i in range(n):self.AddString(result, digits[i])return resultdef AddString(self, result, t):  # 定义一个添加字符串的函数n = len(result)letters = ""if t == '2':letters = "abc"elif t == '3':letters = "def"elif t == '4':letters = "ghi"elif t == '5':letters = "jkl"elif t == '6':letters = "mno"elif t == '7':letters = "pqrs"elif t == '8':letters = "tuv"elif t == '9':letters = "wxyz"if n == 0:result.extend(list(letters))  # 如果结果集为空,直接添加第一个数字对应的字母else:temp_result = []for i in range(n):  # i表示第一个数字所对应的字母的位置for letter in letters:# 将当前结果集中的每个组合与新的字母组合,得到新的结果集temp_result.append(result[i] + letter)result[:] = temp_result  # 用新的结果集替换原有结果集if __name__ == "__main__":solution = Solution()combinations = solution.letterCombinations("234")print(combinations)c++完整代码:
#include<iostream>
#include<vector>using namespace std;class Solution{
public:vector<string> letterCombinations(string digits){int n = digits.length();  //获取输入数字串的长度vector<string> result; //用于存储最终的字母组合结果if(n == 0){return result;}for(int i=0;i<n;++i){AddString(result, digits[i]);  // 调用添加字母函数}return result;}
private:void AddString(vector<string>& result, char digit){int n = result.size();string letters = "";if (digit == '2'){letters = "abc";} else if(digit == '3'){letters = "def";} else if(digit == '4'){letters = "ghi";} else if(digit == '5') {letters = "jkl";} else if(digit == '6'){letters = "mno";} else if(digit == '7'){letters = "pqrs";} else if(digit == '8'){letters = "tuv";} else if(digit == '9'){letters = "wxyz";}if (n == 0){for(char letter : letters){result.push_back(string(1, letter));// 如果结果集为空,直接添加第一个数字对应的字母}} else{vector<string> temp_result;for(int i = 0;i < n; ++i){for(char letter : letters){// 将当前结果集中的每个组合与新的字母组合,得到新的结果集temp_result.push_back(result[i] + letter);}}result = temp_result; // 用新的结果集替换原有结果集}}
};int main(){Solution solution;vector<string> combinations = solution.letterCombinations("234");for(const auto& combination : combinations){cout << combination << endl;}return 0;
}java完整代码:
import java.util.List;
import java.util.ArrayList;
public class LetterCombinations {public List<String> letterCombinations(String digits) {// 获取输入数字串的长度int n = digits.length();// 用于存储最终的字母组合结果List<String> list = new ArrayList();// 如果输入为空字符串,则直接返回空列表if (n == 0) {return list;}// 遍历每个数字字符for (int i = 0; i < n; i++) {// 调用 StringAdd 函数处理每个数字对应的字母StringAdd(list, digits.charAt(i));}return list;}// 定义一个添加字符串的函数public void StringAdd(List<String> list, char t) {// 获取当前结果集的长度int n = list.size();if(t == '2'){  // 处理数字 2 对应的字母组合if(n==0){list.add("a");list.add("b");list.add("c");}else{for(int i=0;i<n;i++){// 遍历当前结果集,为每个组合添加 'a', 'b', 'c',得到新的结果集list.add(list.get(i)+"a");list.add(list.get(i)+"b");list.add(list.get(i)+"c");}for(int i=0;i<n;i++){list.remove(0);}}// 3}else if(t == '3'){if(n==0){list.add("d");list.add("e");list.add("f");}else{for(int i=0;i<n;i++){// 遍历当前结果集,为每个组合添加 'd', 'e', 'f',得到新的结果集list.add(list.get(i)+"d");list.add(list.get(i)+"e");list.add(list.get(i)+"f");}for(int i=0;i<n;i++){list.remove(0);}}// 4}else if(t == '4'){if(n==0){list.add("g");list.add("h");list.add("i");}else{for(int i=0;i<n;i++){// 遍历当前结果集,为每个组合添加 'g', 'h', 'i',得到新的结果集list.add(list.get(i)+"g");list.add(list.get(i)+"h");list.add(list.get(i)+"i");}for(int i=0;i<n;i++){list.remove(0);}}// 5}else if(t == '5'){if(n==0){list.add("j");list.add("k");list.add("l");}else{for(int i=0;i<n;i++){// 遍历当前结果集,为每个组合添加 'j', 'k', 'l',得到新的结果list.add(list.get(i)+"j");list.add(list.get(i)+"k");list.add(list.get(i)+"l");}for(int i=0;i<n;i++){list.remove(0);}}// 6}else if(t == '6'){if(n==0){list.add("m");list.add("n");list.add("o");}else{for(int i=0;i<n;i++){// 遍历当前结果集,为每个组合添加 'm', 'n', 'o',得到新的结果list.add(list.get(i)+"m");list.add(list.get(i)+"n");list.add(list.get(i)+"o");}for(int i=0;i<n;i++){list.remove(0);}}// 7}else if(t == '7'){if(n==0){list.add("p");list.add("q");list.add("r");list.add("s");}else{for(int i=0;i<n;i++){// 遍历当前结果集,为每个组合添加 'p', 'q', 'r', 's',得到新的结果list.add(list.get(i)+"p");list.add(list.get(i)+"q");list.add(list.get(i)+"r");list.add(list.get(i)+"s");}for(int i=0;i<n;i++){list.remove(0);}}// 8}else if(t == '8'){if(n==0){list.add("t");list.add("u");list.add("v");}else{for(int i=0;i<n;i++){// 遍历当前结果集,为每个组合添加 't', 'u', 'v',得到新的结果list.add(list.get(i)+"t");list.add(list.get(i)+"u");list.add(list.get(i)+"v");}for(int i=0;i<n;i++){list.remove(0);}}// 9}else if(t == '9'){if(n==0){list.add("w");list.add("x");list.add("y");list.add("z");}else{for(int i=0;i<n;i++){// 遍历当前结果集,为每个组合添加 'w', 'x', 'y', 'z',得到新的结果list.add(list.get(i)+"w");list.add(list.get(i)+"x");list.add(list.get(i)+"y");list.add(list.get(i)+"z");}for(int i=0;i<n;i++){list.remove(0);}}}}public static void main(String[] args){LetterCombinations solution = new LetterCombinations();List<String> combinations = solution.letterCombinations("234");System.out.println(combinations);}
}
方法2 回溯法
上面我们讨论了通过列举的方法生成结果,但是发现程序写起来实在是太长了,而且看着很low,那么此时我们就可以把数字组合里面每一个数字所对应的字母组合通过一个篮子(哈希表)存起来,要用哪个就拿哪一个,紧接着再通过回溯的方法进行解决,以下是chatgpt所回答的回溯算法:
回溯算法(Backtracking)是一种通过尝试所有可能的候选解并在找到可行解之前放弃部分(或全部)解空间的策略。在问题的解空间中,通过深度优先搜索,一步一步地探索各个可能的解,当发现当前的部分解不能满足问题的约束条件时,就放弃该部分解,回溯到上一步,继续搜索其他可能的解。
回溯算法通常采用递归的方式实现,每一层递归代表问题的一个阶段,通过递归的深入,逐步构建出问题的解。在搜索过程中,如果当前解不满足问题的条件,则回溯到上一步,尝试其他可能的选择。
典型的回溯问题包括组合问题、排列问题、子集问题等。回溯算法通常用于解决组合优化问题,其中问题的解是某种组合的集合,而且问题通常可以分解为多个子问题,通过递归地解决子问题来构建整体的解。
关键特点:
- 状态空间树: 回溯算法可以通过状态空间树的形式进行表示,每个节点代表问题的一个阶段,树的每一层对应算法的一个递归调用。
- 深度优先搜索: 回溯算法采用深度优先搜索的策略,即一条路走到底,如果发现当前路径不能满足问题的条件,就回溯到上一步。
- 剪枝: 在搜索的过程中,可以通过剪枝来减少搜索空间,提高效率。当发现当前部分解无法满足问题的条件时,可以提前结束搜索。
经典的回溯问题包括八皇后问题、0-1背包问题、图的着色问题等。回溯算法的复杂度通常比较高,因此在设计时需要注意优化搜索空间以提高效率。
但是本题不存在不可行的解,所以通过穷举的方法就可以实现。该方法的思路和上述的方法基本上是一致的。

python完整代码:
class Solution:def letterCombinations(self, digits):# 如果输入为空,则直接返回空列表if not digits:return list()# 定义电话号码到字母的映射关系phoneMap = {"2": "abc","3": "def","4": "ghi","5": "jkl","6": "mno","7": "pqrs","8": "tuv","9": "wxyz",}def backtrack(index):# 当前组合字符串长度等于输入数字串长度时,将其加入结果集if index == len(digits):combinations.append("".join(combination))  # 获取当前数字对应的字母集合else:digit = digits[index]  # 将当前字母加入组合字符串,递归调用下一层for letter in phoneMap[digit]:combination.append(letter)backtrack(index + 1)# pop()函数用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值combination.pop()  # 当combinations里面存有adg,紧接着执行for letter in phoneMap[digit]:其中digit=4combination = list()  # 初始化组合列表和当前组合字符串combinations = list()backtrack(0)  # 初始调用回溯函数return combinationsif __name__ == "__main__":# 创建 Solution 对象solution = Solution()# 调用 letterCombinations 函数并输出结果combinations = solution.letterCombinations("234")print(combinations)class Solution:def letterCombinations(self, digits):# 如果输入为空,则直接返回空列表if not digits:return list()# 定义电话号码到字母的映射关系phoneMap = {"2": "abc","3": "def","4": "ghi","5": "jkl","6": "mno","7": "pqrs","8": "tuv","9": "wxyz",}def backtrack(index):# 当前组合字符串长度等于输入数字串长度时,将其加入结果集if index == len(digits):combinations.append("".join(combination))  # 获取当前数字对应的字母集合else:digit = digits[index]  # 将当前字母加入组合字符串,递归调用下一层for letter in phoneMap[digit]:combination.append(letter)backtrack(index + 1)# pop()函数用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值combination.pop()  # 当combinations里面存有adg,紧接着执行for letter in phoneMap[digit]:其中digit=4combination = list()  # 初始化组合列表和当前组合字符串combinations = list()backtrack(0)  # 初始调用回溯函数return combinationsif __name__ == "__main__":# 创建 Solution 对象solution = Solution()# 调用 letterCombinations 函数并输出结果combinations = solution.letterCombinations("234")print(combinations)c++完整代码:
#include<iostream>
#include<vector>
#include<unordered_map>using namespace std;class Solution{
public:vector<string> letterCombination(string digits){unordered_map<char, string> phoneMap = { // 定义数字对应的字母映射关系{'2', "abc"},{'3', "def"},{'4', "ghi"},{'5', "jkl"},{'6', "mno"},{'7', "pqrs"},{'8', "tuv"},{'9', "wxyz"}};// 处理特殊情况,如果输入为空字符串,则直接返回空列表if(digits.empty()){return vector<string> ();}// 用于存储最终的字母组合结果vector<string> result;// 回溯函数,参数分别为当前数字索引和当前已形成的组合字符串backtrack(digits,0,"",phoneMap,result);  //可以试试index等于1是什么结果,就能明白该参数具体指的是什么return result;}
private:// index ---> 数字所对应字母的索引void backtrack(const string& digits, int index, const string& path,const unordered_map<char, string>& phoneMap, vector<string>& result){// 如果当前组合字符串的长度等于输入数字串的长度,将其加入结果集if(index == digits.length()){result.push_back(path);return;}// 获取当前数字对应的字母集合char currentDigit = digits[index];const string& letters = phoneMap.at(currentDigit);// 遍历当前数字对应的字母集合,进行递归回溯for(char letter : letters){// 将当前字母加入组合字符串,递归调用下一层backtrack(digits, index + 1, path + letter, phoneMap, result);}}
};int main(){// 创建 Solution 对象Solution solution;// 调用 letterCombinations 函数并输出结果vector<string> combinations = solution.letterCombination("234");for(const string& combination : combinations){cout << combination << "" << endl;}return 0;
}java完整代码:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class letterCombinations_1 {public List<String> letterCombinations(String digits) {Map<Character, String> phoneMap = new HashMap<>(); // 定义数字对应的字母映射关系phoneMap.put('2', "abc");phoneMap.put('3', "def");phoneMap.put('4', "ghi");phoneMap.put('5', "jkl");phoneMap.put('6', "mno");phoneMap.put('7', "pqrs");phoneMap.put('8', "tuv");phoneMap.put('9', "wxyz");// 处理特殊情况,如果输入为空字符串,则直接返回空列表if (digits == null || digits.isEmpty()) {return new ArrayList<>();}// 用于存储最终的字母组合结果List<String> result = new ArrayList<>();// 回溯函数,参数分别为当前数字索引和当前已形成的组合字符串backtrack(digits, 0, "", phoneMap, result);return result;}private void backtrack(String digits, int index, String path,Map<Character, String> phoneMap, List<String> result) {// 如果当前组合字符串的长度等于输入数字串的长度,将其加入结果集if (index == digits.length()) {result.add(path);return;}// 获取当前数字对应的字母集合char currentDigit = digits.charAt(index);String letters = phoneMap.get(currentDigit);// 遍历当前数字对应的字母集合,进行递归回溯for (char letter : letters.toCharArray()) {// 将当前字母加入组合字符串,递归调用下一层backtrack(digits, index + 1, path + letter, phoneMap, result);}}public static void main(String[] args) {// 创建 Solution 对象letterCombinations_1 solution = new letterCombinations_1();// 调用 letterCombinations 函数并输出结果List<String> combinations = solution.letterCombinations("234");for (String combination : combinations) {System.out.println(combination);}}
}
相关文章:
 
leetcode17 电话号码的字母组合
方法1 if-else方法 if-else方法的思路及其简单粗暴,如下图所示,以数字234为例,数字2所对应的字母是abc,数字3所对应的是def,数字4所对应的是ghi,最后所产生的结果就类似于我们中学所学过的树状图一样&…...
 
用html和css实现一个加载页面【究极简单】
要创建一个简单的加载页面,你可以使用 HTML 和 CSS 来设计。以下是一个基本的加载页面示例: HTML 文件 (index.html): <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"…...
Android-消息机制Handler
Handler的机制:Android 消息传递机制就是handler。在多线程的应用场景中,将工作线程中需更新UI的操作信息 传递到 UI主线程,从而实现对UI的更新处理,最终实现异步消息的处理。多个线程并发更新UI的同时 保证线程安全。Handler只是一个入口&am…...
 
MySQL夯实之路-事务详解
事务四大特性 事务需要通过严格的acid测试。Acid表示原子性,一致性,隔离性,持久性。 原子性(atomicity) 事务是不可分割的最小单元,对于整个事务的操作,要么全部提交成功,要么全部…...
 
安泰电子前置微小信号放大器怎么用的
前置微小信号放大器是一种重要的电子设备,用于放大微弱的输入信号,提高系统的灵敏度。它在各种领域中都有广泛的应用,包括音频、通信、测量等。在这篇文章中,我们将详细介绍前置微小信号放大器的使用方法,以便更好地理…...
 
【深度学习每日小知识】Overfitting 过拟合
过拟合是机器学习(ML)中的常见问题,是指模型过于复杂,泛化能力较差的场景。当模型在有限数量的数据上进行训练,并且学习了特定于该特定数据集的模式,而不是适用于新的、看不见的数据的一般模式时࿰…...
 
嵌入式必备的WEB知识
写在前面 嵌入式要学习Wed前端吗?答案是要的,不需要深入学习,只需要简单了解即可。为什么要学习? 原因如下: 可以远程控制和管理设备:通过简单的Web知识,嵌入式系统可以建立Web界面,…...
Scipy 中级教程——信号处理
Python Scipy 中级教程:信号处理 Scipy 的信号处理模块提供了丰富的工具,用于处理和分析信号数据。在本篇博客中,我们将深入介绍 Scipy 中的信号处理功能,并通过实例演示如何应用这些工具。 1. 信号生成与可视化 首先ÿ…...
 
【排序篇2】选择排序、计数排序
目录 一、选择排序二、计数排序 一、选择排序 整体思想: 从数组中选出最小值和最大值放在起始位置,直到排序完成 具体步骤: 定义两个变量begin和end为下标,指向数组始末定义要找的最大值的下标为maxi,最小值的下标为…...
 
重生奇迹mu敏弓加点攻略
1. 选择正确的属性点分配 在重生奇迹mu游戏中敏弓的属性点分配非常重要。建议将主要属性点分配在敏捷和力量上这样可以提高敏弓的攻击力和闪避能力。适当加点在体力和魔力上可以提高敏弓的生存能力和技能释放次数。不要忘记适当加点在智力上可以提高敏弓的技能威力和命中率。 …...
 
用通俗易懂的方式讲解:一文讲透主流大语言模型的技术原理细节
大家好,今天的文章分享三个方面的内容: 1、比较 LLaMA、ChatGLM、Falcon 等大语言模型的细节:tokenizer、位置编码、Layer Normalization、激活函数等。 2、大语言模型的分布式训练技术:数据并行、张量模型并行、流水线并行、3D …...
 
通过IP地址识别风险用户
随着互联网的迅猛发展,网络安全成为企业和个人关注的焦点之一。识别和防范潜在的风险用户是维护网络安全的关键环节之一。IP数据云将探讨通过IP地址识别风险用户的方法和意义。 IP地址的基本概念:IP地址是互联网上设备的独特标识符,它分为IP…...
汇编和C语言转换
C语言和汇编语言之间有什么区别 C语言和汇编语言之间存在显著的区别,主要体现在以下几个方面: 抽象层次: 汇编语言:更接近硬件的低级语言,通常与特定的处理器或指令集紧密相关。它提供了对处理器指令的直接控制,允许程序员直接操作硬件资源,如寄存器、内存等。 C语言:…...
【IOS】惯性导航详解(包含角度、加速度、修正方式的api分析)
参考文献 iPhone的惯性导航,基于步态。https://www.docin.com/p-811792664.html Inertial Odometry on Handheld Smartphones: https://arxiv.org/pdf/1703.00154.pdf 惯性导航项目相关代码:https://github.com/topics/inertial-navigation-systems use…...
 
Self-Attention
前置知识:RNN,Attention机制 在一般任务的Encoder-Decoder框架中,输入Source和输出Target内容是不一样的,比如对于英-中机器翻译来说,Source是英文句子,Target是对应的翻译出的中文句子,Attent…...
 
网络协议与攻击模拟_04ICMP协议与ICMP重定向
ICMP协议是网络层协议, 利用ICMP协议可以实现网络中监听服务和拒绝服务,如 ICMP重定向的攻击。 一、ICMP基本概念 1、ICMP协议 ICMP是Internet控制报文协议,用于在IP主机、路由器之间传递控制消息,控制消息指网络通不通、主机是…...
pytest-mock 数据模拟
文章目录 mock 测试unittest.mockMock类MagicMock类patch装饰器create_autospec函数断言的方法 pytest-mock 使用 mock 测试 在单元测试时,有些数据需要依赖其他服务或者不好获取到,此时需要使用mock来模拟对应的函数、对象等。 mock模拟数据的python…...
 
单片机原理及应用:定时器/计数器综合应用
本文是《单片机原理及应用》专栏中的最后一篇文章,笔者以编译器的安装配置——51单片机简介——LED和数码管外设——开关和按键控制功能切换——外部中断系统——定时器与计数器为知识大纲,介绍了C语言编程控制51单片机的入门教程。作为收尾,…...
 
R语言【paleobioDB】——pbdb_intervals():通过参数选择,返回多个地层年代段的基本信息
Package paleobioDB version 0.7.0 paleobioDB 包在2020年已经停止更新,该包依赖PBDB v1 API。 可以选择在Index of /src/contrib/Archive/paleobioDB (r-project.org)下载安装包后,执行本地安装。 Usage pbdb_interval (id, ...) Arguments 参数【..…...
 
阅读笔记lv.1
阅读笔记 sql中各种 count结论不同存储引擎计算方式区别count() 类型 责任链模式常见场景例子(闯关游戏) sql中各种 count 结论 innodb count(*) ≈ count(1) > count(主键id) > count(普通索引列) > count(未加索引列)myisam 有专门字段记录…...
 
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
 
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
Git常用命令完全指南:从入门到精通
Git常用命令完全指南:从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...
 
论文阅读:Matting by Generation
今天介绍一篇关于 matting 抠图的文章,抠图也算是计算机视觉里面非常经典的一个任务了。从早期的经典算法到如今的深度学习算法,已经有很多的工作和这个任务相关。这两年 diffusion 模型很火,大家又开始用 diffusion 模型做各种 CV 任务了&am…...
 
sshd代码修改banner
sshd服务连接之后会收到字符串: SSH-2.0-OpenSSH_9.5 容易被hacker识别此服务为sshd服务。 是否可以通过修改此banner达到让人无法识别此服务的目的呢? 不能。因为这是写的SSH的协议中的。 也就是协议规定了banner必须这么写。 SSH- 开头,…...
 
链式法则中 复合函数的推导路径 多变量“信息传递路径”
非常好,我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题,统一使用 二重复合函数: z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y)) 来全面说明。我们会展示其全微分形式(偏导…...
「Java基本语法」变量的使用
变量定义 变量是程序中存储数据的容器,用于保存可变的数据值。在Java中,变量必须先声明后使用,声明时需指定变量的数据类型和变量名。 语法 数据类型 变量名 [ 初始值]; 示例:声明与初始化 public class VariableDemo {publi…...
