LeetCode - 17 电话号码的字母组合

题目来源

17. 电话号码的字母组合 - 力扣(LeetCode)

题目描述

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

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

示例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'] 的一个数字。

题目解析

本题是一个组合问题,可以使用回溯算法解题。

什么是组合问题?

以示例一为例:digits = "23",其中:

  • "2" 对应的可选字母有:'a', 'b', 'c'
  • "3" 对应的可选字母有:'d', 'e', 'f'

因此 "23" 对应的组合有:"ad"、"ae"、"af"、"bd"、"be"、"bf"、"cd"、"ce"、"cf"

如果画图表示的话,可以发现组合问题的求解过程,可以形成一个树形结构。

该树形结构的每一条根到叶子节点的路径都对应一个组合。

因此,如果我们可以遍历出该树形结构的每一条分支,那么就能求出所有组合。

我们可以使用深搜DFS来遍历出树的每一条分支,而深搜本质来说是一种回溯算法。关于回溯算法可以看下:

带你学透回溯算法(理论篇)| 回溯法精讲!_哔哩哔哩_bilibili

C源码实现

cpp 复制代码
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
char *dic[] = {"", "", "abc", "def", "ghi",
               "jkl", "mno", "pqrs", "tuv", "wxyz"};

// 记录所有组合
char **results;
int results_size;

// 用于记录某个组合的临时容器
char path[5] = {'\0'};
int path_size = 0;

/**
 * 回溯算法
 * @param index 表示当前找的是组合的第index个元素
 * @param digits 原始串
 */
void dfs(int index, char *digits) {
    if (path_size == strlen(digits)) { // 组合元素数量达标
        results[results_size] = (char *) calloc(5, sizeof(char));
        strcpy(results[results_size++], path); // 将临时组合记录进结果集
        return;
    }

    // 第index层可选的字母
    char *letters = dic[digits[index] - '0'];

    // 第index层的每一个字母都参与形成组合
    for (int i = 0; i < strlen(letters); i++) {
        path[path_size++] = letters[i]; // 字母letters[i]加入组合
        dfs(index + 1, digits); // 继续进入下层
        path[--path_size] = '\0'; // 回溯
    }
}

char **letterCombinations(char *digits, int *returnSize) {
    // digits长度最大4, 每个数字最多对应4个字母,因此最多产生 4 * 4 * 4 * 4 个组合
    results = (char **) calloc(256, sizeof(char *));
    results_size = 0;

    if (strlen(digits) != 0) {
        dfs(0, digits);
    }

    *returnSize = results_size;
    return results;
}

C++算法源码

cpp 复制代码
class Solution {
public:
    vector<string> dic = {"", "", "abc", "def", "ghi",
                          "jkl", "mno", "pqrs", "tuv", "wxyz"};

    vector<string> letterCombinations(string digits) {
        vector<string> results;

        if (!digits.empty()) {
            dfs(0, "", digits, results);
        }

        return results;
    }

    /**
     * 回溯算法
     * @param index 表示当前找的是组合的第index个元素
     * @param path 用于记录某个组合的临时容器
     * @param digits 原始串
     * @param results 记录所有组合的结果集
     */
    void dfs(int index, string path, string digits, vector<string> &results) {
        if (path.length() == digits.length()) { // 组合元素数量达标
            results.emplace_back(path); // 将临时组合记录进结果集
            return;
        }

        // 第index层可选的字母
        string letters = dic[digits[index] - '0'];

        // 第index层的每一个字母都参与形成组合
        for (int i = 0; i < letters.length(); i++) {
            path.push_back(letters[i]); // 字母letters[i]加入组合
            dfs(index + 1, path, digits, results); // 继续进入下层
            path.pop_back(); // 回溯
        }
    }
};

Java源码实现

java 复制代码
class Solution {
    String[] dic = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};

    public List<String> letterCombinations(String digits) {
        ArrayList<String> results = new ArrayList<>();

        if (!digits.isEmpty()) {
            dfs(0, new StringBuilder(), digits, results);
        }

        return results;
    }

    /**
     * 回溯算法
     *
     * @param index   表示当前找的是组合的第index个元素
     * @param path    用于记录某个组合的临时容器
     * @param digits  原始串
     * @param results 记录所有组合的结果集
     */
    public void dfs(int index, StringBuilder path, String digits, ArrayList<String> results) {
        if (path.length() == digits.length()) { // 组合元素数量达标
            results.add(path.toString()); // 将临时组合记录进结果集
            return;
        }

        // 第index层可选的字母
        String letters = dic[digits.charAt(index) - '0'];

        // 第index层的每一个字母都参与形成组合
        for (int j = 0; j < letters.length(); j++) {
            path.append(letters.charAt(j)); // 字母letters[i]加入组合
            dfs(index + 1, path, digits, results); // 继续进入下层
            path.deleteCharAt(path.length() - 1);  // 回溯
        }
    }
}

Python源码实现

python 复制代码
dic = ("", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz")


def dfs(index, path, digits, results):
    """
    回溯算法
    :param index: 表示当前找的是组合的第index个元素
    :param path: 用于记录某个组合的临时容器
    :param digits: 原始串
    :param results: 记录所有组合的结果集
    :return: void
    """
    if len(path) == len(digits):  # 组合元素数量达标
        results.append("".join(path))  # 将临时组合记录进结果集
        return

    # 第index层可选的字母
    letters = dic[int(digits[index])]

    # 第index层的每一个字母都参与形成组合
    for i in range(len(letters)):
        path.append(letters[i])  # 字母letters[i]加入组合
        dfs(index + 1, path, digits, results)  # 继续进入下层
        path.pop()  # 回溯


class Solution(object):
    def letterCombinations(self, digits):
        """
        :type digits: str
        :rtype: List[str]
        """
        results = []

        if len(digits) > 0:
            dfs(0, [], digits, results)

        return results

JavaScript源码实现

javascript 复制代码
/**
 * @param {string} digits
 * @return {string[]}
 */
const dic = ["", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"];

var letterCombinations = function (digits) {
    const results = [];

    if (digits.length > 0) {
        dfs(0, [], digits, results);
    }

    return results;
};

/**
 * 回溯算法
 * @param {*} index 表示当前找的是组合的第index个元素
 * @param {*} path 用于记录某个组合的临时容器
 * @param {*} digits 原始串
 * @param {*} results 记录所有组合的结果集
 * @returns void
 */
function dfs(index, path, digits, results) {
    if (path.length == digits.length) { // 组合元素数量达标
        results.push(path.join("")); // 将临时组合记录进结果集
        return;
    }

    // 第index层可选的字母
    const letters = dic[parseInt(digits[index])];

    for (let i = 0; i < letters.length; i++) {
        path.push(letters[i]); // 字母letters[i]加入组合
        dfs(index + 1, path, digits, results); // 继续进入下层
        path.pop();  // 回溯
    }
}
相关推荐
许彰午8 小时前
14_Java泛型完全指南
java·windows·python
智慧物业老杨9 小时前
司法绿色通道下的物业纠纷数智化解决方案——基于“三优先“机制的全流程技术落地实践
java·django
2601_961194029 小时前
2026初级会计实务公式总结大全|计算题公式手册PDF
java·spring·eclipse·pdf·tomcat·hibernate
做个文艺程序员9 小时前
第1篇:K8s 核心概念精讲:Pod、Deployment、Service 与 Namespace——Java 开发者快速上手指南
java·云原生·容器·kubernetes·容器编排
广州灵眸科技有限公司9 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) Easy-Eai编译环境准备与更新
服务器·前端·人工智能·python·深度学习
TechWayfarer9 小时前
IP风险等级评估接入实战:金融信贷如何用IP画像辅助风控审核
python·tcp/ip·安全·金融
Esaka_Forever9 小时前
uv init 完整用法(Python 最快包管理器)
服务器·python·uv
sheeta19989 小时前
LeetCode 每日一题笔记 日期:2026.06.02 题目:3635. 最早完成陆地和水上游乐设施的时间 II
笔记·算法·leetcode
Lsk_Smion10 小时前
力扣实训 _ [102].层序遍历--前序--后续_递归与非递归的实现
数据结构·算法·leetcode
小欣加油11 小时前
leetcode3751 范围内总波动值I
java·数据结构·c++·算法·leetcode