LeetCode 第17题:电话号码的字母组合

LeetCode 第17题:电话号码的字母组合

题目描述

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

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

  • 2: abc
  • 3: def
  • 4: ghi
  • 5: jkl
  • 6: mno
  • 7: pqrs
  • 8: tuv
  • 9: wxyz

难度

中等

题目链接

https://leetcode.cn/problems/letter-combinations-of-a-phone-number/

示例

示例 1:

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

示例 2:

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

示例 3:

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

提示

  • 0 <= digits.length <= 4
  • digits[i] 是范围 ['2', '9'] 的一个数字。

解题思路

方法:回溯(深度优先搜索)

这道题可以使用回溯法求解。对于每个数字,我们需要尝试它对应的每个字母,然后继续处理下一个数字。

关键点:

  1. 建立数字到字母的映射表
  2. 使用回溯法遍历所有可能的组合
  3. 使用StringBuilder优化字符串拼接
  4. 处理空字符串的特殊情况

具体步骤:

  1. 处理特殊情况(空字符串)
  2. 初始化数字到字母的映射
  3. 使用回溯法:
    • 当前组合长度等于输入长度时,添加到结果
    • 否则,遍历当前数字对应的所有字母
    • 递归处理下一个数字
    • 回溯,删除最后添加的字母

时间复杂度:O(4^N × N),其中N是输入的长度
空间复杂度:O(N),递归深度

代码实现

C# 实现

public class Solution {
    private readonly string[] phoneMap = {
        "",     // 0
        "",     // 1
        "abc",  // 2
        "def",  // 3
        "ghi",  // 4
        "jkl",  // 5
        "mno",  // 6
        "pqrs", // 7
        "tuv",  // 8
        "wxyz"  // 9
    };
  
    public IList<string> LetterCombinations(string digits) {
        List<string> result = new List<string>();
      
        // 处理空字符串
        if (string.IsNullOrEmpty(digits)) {
            return result;
        }
      
        // 使用StringBuilder优化字符串拼接
        StringBuilder current = new StringBuilder();
        Backtrack(digits, 0, current, result);
      
        return result;
    }
  
    private void Backtrack(string digits, int index, StringBuilder current, List<string> result) {
        // 如果当前组合长度等于输入长度,添加到结果
        if (index == digits.Length) {
            result.Add(current.ToString());
            return;
        }
      
        // 获取当前数字对应的字母
        string letters = phoneMap[digits[index] - '0'];
      
        // 遍历当前数字对应的所有字母
        for (int i = 0; i < letters.Length; i++) {
            // 添加当前字母
            current.Append(letters[i]);
          
            // 递归处理下一个数字
            Backtrack(digits, index + 1, current, result);
          
            // 回溯,删除最后添加的字母
            current.Length--;
        }
    }
}

优化版本(使用队列)

public class Solution {
    private readonly string[] phoneMap = {
        "",     // 0
        "",     // 1
        "abc",  // 2
        "def",  // 3
        "ghi",  // 4
        "jkl",  // 5
        "mno",  // 6
        "pqrs", // 7
        "tuv",  // 8
        "wxyz"  // 9
    };
  
    public IList<string> LetterCombinations(string digits) {
        List<string> result = new List<string>();
      
        // 处理空字符串
        if (string.IsNullOrEmpty(digits)) {
            return result;
        }
      
        // 初始化结果为空字符串
        result.Add("");
      
        // 逐个处理每个数字
        foreach (char digit in digits) {
            List<string> temp = new List<string>();
            string letters = phoneMap[digit - '0'];
          
            // 将当前数字的每个字母与之前的结果组合
            foreach (string s in result) {
                foreach (char letter in letters) {
                    temp.Add(s + letter);
                }
            }
          
            result = temp;
        }
      
        return result;
    }
}

代码详解

回溯版本:

  1. 映射表定义:
    • 使用字符串数组存储数字到字母的映射
  2. 回溯函数:
    • 使用StringBuilder优化字符串操作
    • 递归处理每个数字对应的字母
    • 使用index跟踪处理位置
  3. 结果收集:
    • 当处理完所有数字时添加结果
    • 回溯时删除最后添加的字母

队列版本:

  1. 迭代处理:
    • 逐个处理每个数字
    • 使用临时列表存储新的组合
  2. 组合生成:
    • 将当前数字的每个字母与之前的结果组合
    • 更新结果列表
  3. 优化:
    • 避免使用递归
    • 减少内存使用

执行结果

回溯版本:

  • 执行用时:132 ms
  • 内存消耗:42.8 MB

队列版本:

  • 执行用时:124 ms
  • 内存消耗:42.5 MB

总结与反思

  1. 这道题的关键点:
    • 理解回溯法的应用
    • 字符串组合的生成
    • 优化字符串操作
  2. 两种解法比较:
    • 回溯法:思路清晰,适合扩展
    • 队列法:性能更好,代码更简洁
  3. 优化思路:
    • 使用StringBuilder提高性能
    • 预分配结果集大小
    • 考虑并行处理大规模输入

相关题目

posted @   旧厂街小江  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示