当前位置: 首页 > news >正文

今日算法(组合问题)(回溯解法)

题目描述

给定一个仅包含数字2-9的字符串,返回所有它能表示的字母组合。答案可以按任意顺序返回。 数字到字母的映射与电话按键相同,1 不对应任何字母。

示例 1:

  • 输入:digits = "23"
  • 输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]

示例 2:

  • 输入:digits = "2"
  • 输出:["a","b","c"]

解法一:回溯法(递归)

核心思路

这道题本质上是多叉树的深度优先搜索(DFS)

  • 每个数字对应一组字母,相当于树的一层
  • 我们需要遍历每一层的所有字母,组合出所有可能的路径
  • 当路径长度等于输入数字的长度时,就得到了一个有效组合

代码实现(C++)

class Solution { public: vector<string> letterCombinations(string digits) { vector<string> res; if (digits.empty()) return res; // 数字到字母的映射表 unordered_map<char, string> phoneMap = { {'2', "abc"}, {'3', "def"}, {'4', "ghi"}, {'5', "jkl"}, {'6', "mno"}, {'7', "pqrs"}, {'8', "tuv"}, {'9', "wxyz"} }; string path; // 保存当前路径 backtrack(digits, 0, phoneMap, path, res); return res; } private: // index:当前处理到第几个数字 void backtrack(const string& digits, int index, const unordered_map<char, string>& phoneMap, string& path, vector<string>& res) { // 终止条件:路径长度等于数字长度 if (index == digits.size()) { res.push_back(path); return; } // 获取当前数字对应的所有字母 char digit = digits[index]; const string& letters = phoneMap.at(digit); // 遍历所有可能的字母 for (char letter : letters) { // 1. 选择当前字母 path.push_back(letter); // 2. 递归处理下一个数字 backtrack(digits, index + 1, phoneMap, path, res); // 3. 回溯:撤销选择,尝试下一个字母 path.pop_back(); } } };

详细步骤解析

以输入"23"为例,模拟回溯过程:

  1. 初始状态path = ""index = 0(处理第一个数字'2'
  2. 处理数字'2',对应字母"abc"
    • 'a'path = "a",递归处理下一个数字index=1
      • 处理数字'3',对应字母"def"
        • 'd'path = "ad",长度等于 2,加入结果集
        • 'e'path = "ae",加入结果集
        • 'f'path = "af",加入结果集
      • 回溯:path = "a"
    • 'b'path = "b",递归处理下一个数字,生成"bd", "be", "bf"
    • 'c'path = "c",递归处理下一个数字,生成"cd", "ce", "cf"
  3. 最终结果:所有组合都已加入res,返回结果集。

复杂度分析

  • 时间复杂度:\(O(3^N \times 4^M)\)
    • N是对应 3 个字母的数字个数(2,3,4,5,6,8)
    • M是对应 4 个字母的数字个数(7,9)
  • 空间复杂度:\(O(N+M)\)
    • 递归栈深度等于输入数字的长度,路径path的最大长度也为N+M

解法二:迭代法(队列模拟)

核心思路

用队列模拟组合的生成过程,每次取出队列中已有的组合,与当前数字的所有字母拼接,生成新的组合,再放回队列。

代码实现(C++)

class Solution { public: vector<string> letterCombinations(string digits) { vector<string> res; if (digits.empty()) return res; // 数字到字母的映射表 vector<string> phoneMap = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; queue<string> q; q.push(""); // 初始空字符串 for (char digit : digits) { int levelSize = q.size(); // 当前队列中的组合数量 string letters = phoneMap[digit - '0']; // 处理当前层的所有组合 for (int i = 0; i < levelSize; ++i) { string current = q.front(); q.pop(); // 拼接当前数字的所有字母,生成新组合 for (char letter : letters) { q.push(current + letter); } } } // 队列中剩余的元素就是所有组合 while (!q.empty()) { res.push_back(q.front()); q.pop(); } return res; } };

详细步骤解析

同样以输入"23"为例:

  1. 初始状态:队列q = [""]
  2. 处理数字'2'(对应"abc"):
    • 取出"",拼接"a", "b", "c",得到"a", "b", "c",放回队列
    • 队列变为:["a", "b", "c"]
  3. 处理数字'3'(对应"def"):
    • 取出"a",拼接"d", "e", "f""ad", "ae", "af",放回队列
    • 取出"b",拼接"d", "e", "f""bd", "be", "bf",放回队列
    • 取出"c",拼接"d", "e", "f""cd", "ce", "cf",放回队列
    • 队列变为:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]
  4. 遍历队列,得到最终结果

两种解法对比

表格

对比维度回溯法(递归)迭代法(队列)
代码简洁度更直观,逻辑清晰稍复杂,需要手动维护队列
理解难度符合人类思维,容易理解需要理解组合生成的过程
空间复杂度递归栈深度为数字长度队列需要存储中间结果
适用场景数字长度不大时(本题长度≤4)无递归深度限制,适合所有场景

总结

  • 这道题是回溯算法的入门经典题,核心是理解 “选择 - 递归 - 回溯” 的过程。
  • 回溯法的关键是:用一个路径变量保存当前组合,递归处理每一层,处理完后撤销选择
  • 迭代法是回溯法的非递归实现,用队列模拟组合的生成过程,避免了递归栈溢出的风险。
http://www.jsqmd.com/news/887715/

相关文章:

  • Allegro等长设置翻车实录:拓扑模板法的3个坑与手工PinPair的救赎
  • 别再只调API了!用Python+OpenCV实战拆解RGB到YCbCr灰度转换的每一步(附避坑指南)
  • 怎么知道机械臂该怎么动
  • 合肥代理记账权威机构判定维度与合规服务解析:合肥工商注册代理/合肥注册公司名称核准/合肥注册公司地址挂靠/合肥注册公司材料/选择指南 - 优质品牌商家
  • Unity项目里用EnhancedScroller v2.15.6做排行榜,5分钟搞定数据绑定和滚动优化
  • 别再死记硬背了!用Multisim仿真+图解,5分钟搞懂三极管共射放大电路工作原理
  • 3分钟快速上手:如何在浏览器中免费将HTML转换为Word文档
  • 深入OpenPnP视觉校准:从‘模糊Mark点’到‘白平衡优化’的调试实录
  • 别再傻傻分不清了!5分钟搞懂点乘和叉乘在游戏开发里的实际用法(Unity/C#)
  • 深度学习从心电信号中解码呼吸频率:原理、实现与临床价值
  • 告别命令行!用Python脚本批量管理Docker容器,效率提升不止一点点
  • whisper语音转文字配置
  • 告别玄学修蓝屏:用Windows事件查看器和可靠性监视器精准诊断‘PAGE_FAULT’错误
  • SPT-AKI Profile Editor终极指南:完全掌控你的离线塔科夫存档修改
  • Unity游戏资源提取实战指南:AssetStudio核心原理与免费提取教程
  • 2026年近期剖析:温州不错的GEO优化直销企业市场价值 - 2026年企业推荐榜
  • 手把手教你用CTSpine1K和OAI-ZIB数据集,快速搭建医学影像分析环境(附代码)
  • 2026年05月排污泵优选:这些供货商值得一看,户外泵房/光伏太阳能供水设备/潜水排污泵,排污泵制造企业哪家好 - 品牌推荐师
  • 当有限元遇上游戏引擎:用Unity重现Abaqus应力云图的完整流程
  • Unity真机帧率监控:解耦CPU/GPU/Present三帧率
  • C++中显示与隐式加载dll的使用与区别
  • 什么是吱吱OC|2026
  • Unity安卓构建72小时实战指南:从零到真机运行
  • 2026年全国瓷砖美缝剂主流品牌盘点与实测对比:屋顶防水材料、强力瓷砖背胶、强力瓷砖胶、新型防水材料、柔性瓷砖胶选择指南 - 优质品牌商家
  • SSH私钥权限600原理与Linux文件系统安全机制解析
  • 基于肠道菌群与机器学习的帕金森病早期诊断模型BDPM详解
  • Simulink仿真避坑指南:单相全桥逆变电路方波驱动相位设置(θ=30° vs 60°)对输出波形的影响深度对比
  • AssetStudio深度解析:Unity资源加载原理与故障排除实战
  • Unity安卓打包实战指南:从环境配置到APK生成全链路排错
  • 从测速到配置:一套完整的cFosSpeed网络加速保姆级教程(适用于小白)