leetcode17.电话号码的字母组合:字符串映射与回溯的巧妙联动
一、题目深度解析与字符映射逻辑
题目描述
给定一个仅包含数字 2-9
的字符串 digits
,返回所有它能表示的字母组合。数字与字母的映射关系如下(与电话按键相同):
2: "abc", 3: "def", 4: "ghi", 5: "jkl",
6: "mno", 7: "pqrs", 8: "tuv", 9: "wxyz"
例如,输入 digits = "23"
,应返回 ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]
。题目要求:
- 输出的字母组合需包含所有可能情况
- 每个数字对应字母的不同组合都要考虑
- 结果顺序不做要求
核心难点剖析
本题的关键在于如何根据数字字符串的每个字符,找到对应的字母集合,并通过回溯算法生成所有可能的组合。其中,数字与字母的映射关系需要通过数据结构记录,而回溯过程中的状态管理则是确保组合完整性的核心。
二、递归回溯解法的核心实现与逻辑框架
class Solution {// 数字到字母的映射数组,0和1无对应字母,用空字符串占位String[] numString = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};List<String> res = new ArrayList<>(); // 存储所有结果组合StringBuilder sb = new StringBuilder(); // 记录当前组合public List<String> letterCombinations(String digits) {if (digits.length() == 0) {return res; // 处理空字符串输入}backtracking(digits, 0); // 从第一个数字开始回溯return res; // 返回所有组合}public void backtracking(String digits, int num) {if (num == digits.length()) {res.add(sb.toString()); // 保存当前组合return;}// 获取当前数字对应的字母字符串String str = numString[digits.charAt(num) - '0'];for (int i = 0; i < str.length(); i++) {sb.append(str.charAt(i)); // 选择当前字母backtracking(digits, num + 1); // 递归处理下一个数字sb.deleteCharAt(sb.length() - 1); // 回溯:撤销当前选择}}
}
核心设计解析
- 字符映射数组:
numString
数组建立数字与字母的映射关系,通过numString[digits.charAt(num) - '0']
可快速获取对应字母集合。其中,- '0'
的操作将字符类型的数字转换为数组索引所需的整数类型。
- 结果与状态变量:
res
:使用ArrayList
存储所有符合要求的字母组合。sb
:StringBuilder
用于高效构建当前组合,避免频繁字符串拼接带来的性能损耗。
- 递归终止条件:
if (num == digits.length())
:当处理完数字字符串的所有字符时,将当前sb
记录的组合加入res
,并结束当前递归分支。
- 回溯核心逻辑:
- 遍历当前数字对应的字母字符串,每次选择一个字母加入
sb
。 - 递归调用
backtracking
处理下一个数字。 - 递归返回后,通过
sb.deleteCharAt(sb.length() - 1)
删除最后一个字母,回溯到上一状态,尝试其他可能的组合。
- 遍历当前数字对应的字母字符串,每次选择一个字母加入
三、核心问题解析:字符串映射与回溯联动
1. 数字字符到字母集合的映射实现
numString
数组是连接数字与字母的桥梁。以输入字符串"23"
为例:
- 处理第一个数字
'2'
时,numString[2 - '0']
获取到"abc"
,即数字2
对应的字母集合。 - 处理第二个数字
'3'
时,numString[3 - '0']
获取到"def"
。
这种映射方式通过数组下标直接定位,时间复杂度为O(1),相比使用Map
等数据结构更加简洁高效。
2. 回溯算法的具体执行逻辑
在backtracking
方法中,回溯过程通过递归与状态回退实现:
- 选择阶段:
每次从当前数字对应的字母集合中选择一个字母加入sb.append(str.charAt(i)); backtracking(digits, num + 1);
sb
,并递归处理下一个数字,深入探索当前选择下的所有可能组合。 - 回退阶段:
递归返回后,删除sb.deleteCharAt(sb.length() - 1);
sb
中最后一个字母,撤销当前选择,以便尝试该数字对应的其他字母,确保所有组合都能被枚举到。
3. 递归过程中的状态传递
在递归调用过程中,num
参数记录当前处理的数字位置,sb
则记录当前构建的组合状态。每一层递归都基于上一层的状态继续构建,确保组合的完整性和准确性。例如:
- 当处理数字字符串
"23"
时,第一层递归处理数字2
,第二层递归处理数字3
。在第二层递归中,sb
已包含第一层递归选择的字母(如'a'
),在此基础上继续添加数字3
对应的字母(如'd'
),最终形成组合"ad"
。
四、递归流程深度模拟:以输入"23"为例
- 初始调用:
backtracking("23", 0)
num = 0
,处理第一个数字'2'
,str = "abc"
。
- 选择字母
'a'
:sb.append('a')
,此时sb = "a"
。- 递归调用
backtracking("23", 1)
,处理第二个数字'3'
,str = "def"
。 - 选择字母
'd'
,sb.append('d')
,此时sb = "ad"
,满足终止条件,将"ad"
加入res
。 - 回溯:
sb.deleteCharAt(sb.length() - 1)
,sb
变回"a"
,继续选择字母'e'
,形成"ae"
并加入res
,以此类推,完成数字3
对应字母的所有组合。
- 回到数字
2
的处理:- 撤销字母
'a'
的选择,sb.deleteCharAt(sb.length() - 1)
,sb
清空。 - 选择字母
'b'
,重复上述递归过程,生成以'b'
开头的所有组合(如"bd"
、"be"
、"bf"
)。
- 撤销字母
- 选择字母
'c'
:- 同样进行递归与回溯,生成以
'c'
开头的所有组合(如"cd"
、"ce"
、"cf"
)。
- 同样进行递归与回溯,生成以
- 最终结果:
res
包含["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]
,涵盖所有可能的字母组合。
五、算法复杂度分析
1. 时间复杂度
假设数字字符串digits
的长度为n
,每个数字平均对应m
个字母(实际最多4个)。
- 对于每个数字,都需要遍历其对应的字母集合,因此时间复杂度为 O ( m n ) O(m^n) O(mn) 。因为每个数字位置都有
m
种选择,总共n
个位置,属于指数级复杂度。
2. 空间复杂度
- 递归栈的深度最大为
n
,因此空间复杂度为 O ( n ) O(n) O(n) 。 res
存储所有结果组合,最坏情况下,组合数量为 m n m^n mn,每个组合长度为n
,因此res
占用空间为 O ( n × m n ) O(n \times m^n) O(n×mn) 。整体空间复杂度主要由res
决定,为 O ( n × m n ) O(n \times m^n) O(n×mn) 。
六、核心技术点总结:字母组合生成的关键要素
- 字符映射设计:通过数组建立数字与字母的高效映射,简化查找过程。
- 回溯状态管理:利用
StringBuilder
动态构建组合,并通过递归与回退操作确保枚举所有可能组合。 - 递归终止条件:根据数字字符串的处理进度判断是否完成一个组合的构建,及时保存结果。
七、常见误区与优化建议
1. 字符转换错误
- 误区:遗漏
- '0'
操作,导致无法正确获取字母集合。String str = numString[digits.charAt(num)]; // 错误,未转换字符为数字
- 正确做法:使用
numString[digits.charAt(num) - '0']
将字符类型数字转换为数组索引。
2. 回溯状态未完全回退
- 误区:在递归返回后,未删除
sb
中的最后一个字母,导致后续组合错误。sb.append(str.charAt(i)); backtracking(digits, num + 1); // 缺少 sb.deleteCharAt(sb.length() - 1);
- 正确做法:确保在每次递归返回后,通过
sb.deleteCharAt(sb.length() - 1)
撤销当前选择。
3. 优化建议:迭代实现
若担心递归深度过深导致栈溢出,可以考虑使用迭代方式,借助队列或栈模拟递归过程。例如,使用队列存储中间状态,每次从队列中取出一个状态,扩展下一个数字对应的字母组合并重新入队,直至处理完所有数字。这种方式可以将空间复杂度优化为 O ( m n ) O(m^n) O(mn) ,避免递归栈的潜在风险。
通过对本题递归回溯解法的详细剖析,我们深入理解了如何利用字符串映射和回溯算法,高效生成电话号码对应的字母组合。这种解题思路在处理组合枚举类问题时具有广泛的应用价值,能够帮助我们解决更多类似的算法问题。
相关文章:
leetcode17.电话号码的字母组合:字符串映射与回溯的巧妙联动
一、题目深度解析与字符映射逻辑 题目描述 给定一个仅包含数字 2-9 的字符串 digits,返回所有它能表示的字母组合。数字与字母的映射关系如下(与电话按键相同): 2: "abc", 3: "def", 4: "ghi", …...

Gartner《2025 年软件工程规划指南》报告学习心得
一、引言 软件工程领域正面临着前所未有的变革与挑战。随着生成式人工智能(GenAI)等新兴技术的涌现、市场环境的剧烈动荡以及企业对软件工程效能的更高追求,软件工程师们必须不断适应和拥抱变化,以提升自身竞争力并推动业务发展。Gartner 公司发布的《2025 年软件工程规划…...
数据库 | 使用timescaledb和大模型进行数据分析
时序数据库:timescaledb 大模型:通义千问2.5 对话开始前提示词: 我正在做数据分析,以下是已知信息: 数据库:timescaledb,表名:dm_tag_value,tag_name列是位号名,app_time列是时间,…...
快速阅读源码
Doxygen 轻松生成包含类图、调用关系图的 HTML 和 PDF 文档, Graphviz 可以用来生成类图、调用图 sudo apt-get install doxygen graphviz brew install doxygen graphviz#HTML 文档: open docs/html/index.html一、Doxyfile配置: Doxyfile 文件 doxygen Doxyfile P…...
linux创建虚拟网卡和配置多ip
1.展示当前网卡信息列表: linux上: ip a ifconfigwindows上: ipconfig 2.创建虚拟网卡对: sudo ip link add name veth0 type veth peer name veth1 在 ip link add 命令中,type 参数可以指定多种虚拟网络设备类型&…...

Java Class类文件结构
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,…...
AI问答-Vue3+TS:reactive创建一个响应式数组,用一个新的数组对象来替换它,同时保持响应性
在 Vue 3 中,当你使用 reactive 创建一个响应式数组后,如果你想用一个新的数组对象来替换它,同时保持响应性,有几种方法可以实现 方法一:直接替换整个数组(推荐) import { reactive } from vu…...

quasar electron mode如何打包无边框桌面应用程序
预览 开源项目Tokei Kun 一款简洁的周年纪念app,现已发布APK(安卓)和 EXE(Windows) 项目仓库地址:Github Repo 应用下载链接:Github Releases Preparation for Electron quasar dev -m elect…...

【HW系列】—Windows日志与Linux日志分析
文章目录 一、Windows日志1. Windows事件日志2. 核心日志类型3. 事件日志分析实战详细分析步骤 二、Linux日志1. 常见日志文件2. 关键日志解析3. 登录爆破检测方法日志分析核心要点 一、Windows日志 1. Windows事件日志 介绍:记录系统、应用程序及安全事件&#x…...

VIN码识别解析接口如何用C#进行调用?
一、什么是VIN码识别解析接口? VIN码不仅是车辆的“身份证”,更是连接制造、销售、维修、保险、金融等多个环节的数字纽带。而VIN码查询API,正是打通这一链条的关键工具。 无论是汽车电商平台、二手车商、维修厂,还是保险公司、金…...

动态规划之网格图模型(一)
文章目录 动态规划之网格图模型(一)LeetCode 64. 最小路径和思路Golang 代码 LeetCode 62. 不同路径思路Golang 代码 LeetCode 63. 不同路径 II思路Golang 代码 LeetCode 120. 三角形最小路径和思路Golang 代码 LeetCode 3393. 统计异或值为给定值的路径…...

PCB设计实践(三十)地平面完整性
在高速数字电路和混合信号系统设计中,地平面完整性是决定PCB性能的核心要素之一。本文将从电磁场理论、信号完整性、电源分配系统等多个维度深入剖析地平面设计的关键要点,并提出系统性解决方案。 一、地平面完整性的电磁理论基础 电流回流路径分析 在PC…...
x86_64-apple-ios-simulator 错误
Could not find module ImagePicker for target x86_64-apple-ios-simulator; found: arm64, arm64-apple-ios-simulator 解决方案一 添加 arm64。 搜索 Excluded Architectures ,添加arm64 解决方案二 在Podfild中,添加佐料。在文件的最下方添加如…...

使用ray扩展python应用之流式处理应用
流式处理就是数据一来,咱们就得赶紧处理,不能攒批再算。这里的实时不是指瞬间完成,而是要在数据产生的那一刻,或者非常接近那个时间点,就做出响应。这种处理方式,我们称之为流式处理。 流式处理的应用场景…...

IP证书的作用与申请全解析:从安全验证到部署实践
在网络安全领域,IP证书(IP SSL证书)作为传统域名SSL证书的补充方案,专为公网IP地址提供HTTPS加密与身份验证服务。本文将从技术原理、应用场景、申请流程及部署要点四个维度,系统解析IP证书的核心价值与操作指南。 一…...
第四十一天打卡
简单CNN 知识回顾 数据增强 卷积神经网络定义的写法 batch归一化:调整一个批次的分布,常用与图像数据 特征图:只有卷积操作输出的才叫特征图 调度器:直接修改基础学习率 卷积操作常见流程如下: 1. 输入 → 卷积层 →…...
C++中指针常量和常量指针的区别
C中指针常量和常量指针的区别 前言 在 C/C 编程中,指针是一个非常重要的概念,而指针常量和常量指针又是指针的两种特殊形式,它们在实际开发中有着不同的应用场景和语义,理解它们的区别对于编写高质量的代码至关重要。本文将详细…...
深入解析向量数据库:基本原理与主流实现
向量数据库(Vector Database)是专门用于存储和检索高维向量的数据库系统。近年来,随着机器学习和深度学习的发展,文本、图像、音频等非结构化数据常被转换为向量表示,用于语义搜索和推荐等场景。这篇博客将面向 Java/P…...
VectorNet:自动驾驶中的向量魔法
在自动驾驶的世界里,车辆需要像超级英雄一样,拥有“透视眼”和“预知未来”的能力,才能在复杂的交通环境中安全行驶。今天,我们要介绍一个神奇的工具——VectorNet,它就像是给自动驾驶车辆装上了一双智能的眼睛&#x…...
PostgreSQL性能监控双雄:深入解析pg_stat_statements与pg_statsinfo
在PostgreSQL的运维和优化工作中,性能监控工具的选择直接关系到问题定位的效率和数据库的稳定性。今天我们将深入探讨两款核心工具:pg_stat_statements(SQL执行统计)和pg_statsinfo(系统级监控),…...

【Linux系列】Linux/Unix 系统中的 CPU 使用率
博客目录 多核处理器时代的 CPU 使用率计算为什么要这样设计? 解读实际案例:268.76%的 CPU 使用率性能分析的意义 相关工具与监控实践1. top 命令2. htop 命令3. mpstat 命令4. sar 命令 实际应用场景容量规划性能调优故障诊断 深入理解:CPU …...

C++语法系列之模板进阶
前言 本次会介绍一下非类型模板参数、模板的特化(特例化)和模板的可变参数,不是最开始学的模板 一、非类型模板参数 字面意思,比如: template<size_t N 10> 或者 template<class T,size_t N 10>比如:静态栈就可以用到&#…...

基于图神经网络的自然语言处理:融合LangGraph与大型概念模型的情感分析实践
在企业数字化转型进程中,非结构化文本数据的处理与分析已成为核心技术挑战。传统自然语言处理方法在处理客户反馈、社交媒体内容和内部文档等复杂数据集时,往往难以有效捕获文本间的深层语义关联和结构化关系。大型概念模型(Large Concept Mo…...

R 语言科研绘图 --- 热力图-汇总
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
基于DFT码本的波束方向图生成MATLAB实现
基于DFT码本的波束方向图生成MATLAB实现,包含参数配置、方向图生成和可视化模块: %% 基于DFT码本的波束方向图生成 clc; clear; close all;%% 参数配置 params struct(...N, 8, % 阵元数d, 0.5, % 阵元间距(λ/2)theta_sc…...
vBulletin未认证API方法调用漏洞(CVE-2025-48827)
免责声明 本文档所述漏洞详情及复现方法仅限用于合法授权的安全研究和学术教育用途。任何个人或组织不得利用本文内容从事未经许可的渗透测试、网络攻击或其他违法行为。使用者应确保其行为符合相关法律法规,并取得目标系统的明确授权。 对于因不当使用本文信息而造成的任何直…...

解决访问网站提示“405 很抱歉,由于您访问的URL有可能对网站造成安全威胁,您的访问被阻断”问题
一、问题描述 本来前几天都可以正常访问的网站,但是今天当我们访问网站的时候会显示“405 很抱歉,由于您访问的URL有可能对网站造成安全威胁,您的访问被阻断。您的请求ID是:XXXX”,而不能正常的访问网站,如…...
FeignClient发送https请求时的证书验证原理分析
背景 微服务之间存在调用关系,且部署为 SSL 协议时,Feignt 请求报异常: Caused by: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find vali…...
UDP组播套接字与URI/URL/URN技术详解
UDP组播套接字基础 Java通过MulticastSocket类提供对UDP组播通信的支持,该机制允许单个数据报同时发送给多个接收者。组播套接字的工作机制与标准DatagramSocket类似,但核心区别在于其基于组播组成员关系的通信模型。 组播组成员管理 创建并绑定组播套接字后,必须调用joi…...

机器学习中的关键术语及其含义
神经元及神经网络 机器学习中的神经网络是一种模仿生物神经网络的结构和功能的数学模型或计算模型。它是指按照一定的规则将多个神经元连接起来的网络。 神经网络是一种运算模型,由大量的节点(或称神经元)之间相互联接构成。每个节点代表一…...