返回

借力BFS、DFS算法,轻松通关LeetCode电话号码的字母组合难题

前端

电话号码字母组合,一个看似简单却蕴含深刻算法思想的编程难题,正在等待着你的探索和征服。

背景概述

在计算机领域,算法的出现为我们解决复杂问题提供了强有力的工具。而在算法世界中,广度优先搜索(BFS)和深度优先搜索(DFS)则堪称两大重要支柱,它们各自的特点和应用场景也备受程序员们的青睐。

题目剖析

LeetCode电话号码字母组合难题的题意很简单:给你一个电话号码,每个数字对应一组字母,要求你找出所有可能的字母组合。

例如,对于电话号码 "23",其对应的字母组合包括:

  • "ad"
  • "ae"
  • "af"
  • "bd"
  • "be"
  • "bf"
  • "cd"
  • "ce"
  • "cf"

BFS 与 DFS 的选择

面对这道难题,我们首先需要考虑选择哪种算法更适合解决。BFS 和 DFS 都是探索图或树形结构的有效算法,但它们各有千秋。

BFS 以广度优先的方式探索所有可能的状态,从根节点开始,先将根节点的所有邻接节点加入队列,然后依次处理队列中的每个节点,直到队列为空。这种方法的好处在于,它可以保证找到最短路径。

DFS 则以深度优先的方式探索所有可能的状态,从根节点开始,一直沿着某条路径深入探索,直到达到叶子节点或遇到死胡同,然后再回溯到上一个节点,继续探索其他路径。这种方法的好处在于,它可以更早地找到目标节点。

针对本题,我们使用深度优先搜索(DFS)来解决。

DFS算法实现

在实现代码之前,我们先来缕清解决问题的思路:

  1. 首先,我们定义一个字母字典,将数字与对应的字母组合一一对应。
  2. 然后,我们使用递归的方式来探索所有可能的组合。在每个递归步骤中,我们从给定电话号码中取出一个数字,并将其对应的字母组合添加到当前的组合中。
  3. 当我们探索完所有的数字后,我们将当前的组合加入结果列表中。
/**
 * 给定一个电话号码,返回所有可能的字母组合。
 *
 * @param {string} digits 电话号码
 * @return {string[]} 所有可能的字母组合
 */
const letterCombinations = (digits) => {
  if (digits === null || digits.length === 0) {
    return [];
  }

  // 定义字母字典
  const letters = {
    '2': ['a', 'b', 'c'],
    '3': ['d', 'e', 'f'],
    '4': ['g', 'h', 'i'],
    '5': ['j', 'k', 'l'],
    '6': ['m', 'n', 'o'],
    '7': ['p', 'q', 'r', 's'],
    '8': ['t', 'u', 'v'],
    '9': ['w', 'x', 'y', 'z'],
  };

  // 定义结果列表
  const result = [];

  // 定义当前组合
  const currentCombination = [];

  // 开始探索所有可能的组合
  exploreCombinations(digits, 0, letters, currentCombination, result);

  // 返回结果列表
  return result;
};

/**
 * 递归探索所有可能的组合。
 *
 * @param {string} digits 电话号码
 * @param {number} index 当前探索的数字索引
 * @param {object} letters 字母字典
 * @param {string[]} currentCombination 当前的组合
 * @param {string[]} result 结果列表
 */
const exploreCombinations = (digits, index, letters, currentCombination, result) => {
  // 如果已经探索完所有的数字
  if (index === digits.length) {
    // 将当前组合加入结果列表
    result.push(currentCombination.join(''));
    return;
  }

  // 获取当前数字对应的字母组合
  const lettersForDigit = letters[digits[index]];

  // 循环遍历当前数字对应的字母组合
  for (let i = 0; i < lettersForDigit.length; i++) {
    // 将当前字母添加到当前组合中
    currentCombination.push(lettersForDigit[i]);

    // 继续探索下一个数字
    exploreCombinations(digits, index + 1, letters, currentCombination, result);

    // 从当前组合中移除当前字母
    currentCombination.pop();
  }
};

结语

通过本文,你已经掌握了两种算法的精髓,并且成功地将它们应用到LeetCode电话号码字母组合难题的求解中。希望你能够学以致用,在未来的编程实践中灵活地选择和使用合适的算法,书写出更加优雅和高效的代码。