LeetCode探索(65):17-电话号码的字母组合

121 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第22天,点击查看活动详情

题目

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

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

img

示例 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中的每个数字所能表示的所有字母组合。我们可以借助回溯算法去解决该问题。回溯算法用于寻找所有的可行解,如果发现一个解不可行,则会舍弃,并继续寻找新的解。在回溯过程中,当达到约束条件(本题中约束条件是得出的字符串长度刚好为digits数组的长度)时,就跳出本次递归,并继续下一轮的回溯。

具体是,在回溯过程中维护一个字符串str,表示已有的字母组合。每次取出给出的电话号码中的一位数字,获得该数字对应的所有可能的字母,并将其中的一个字母取出,继续进行递归处理。然后进行回退操作,遍历其余的字母排列。

解答

方法一:回溯算法

/**
 * @param {string} digits
 * @return {string[]}
 */
var letterCombinations = function (digits) {
  if (digits.length === 0) return []
  // 数字到字母的映射
  const mapping = ['', '', 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']
  const res = []
  // 回溯算法主函数
  const backtrack = (digits, start, str) => {
    // 回溯结束
    if (str.length === digits.length) {
      res.push(str)
      return
    }
    // 遍历digits中的数字
    for (let i = start; i < digits.length; i++) {
      // 对于每个数字digits[i],找到数字对应的字母
      let digit = digits[i]
      for (let c of mapping[digit]) {
        // 做选择
        str += c
        // 递归下一层回溯树
        backtrack(digits, i + 1, str)
        // 撤销选择
        str = str.slice(0, -1)
      }
    }
  }
  backtrack(digits, 0, '')
  return res
}
// console.log(letterCombinations("23")) // ["ad","ae","af","bd","be","bf","cd","ce","cf"]// 执行用时:56 ms, 在所有 JavaScript 提交中击败了85.61%的用户
// 内存消耗:41.1 MB, 在所有 JavaScript 提交中击败了53.49%的用户
// 通过测试用例:25 / 25

复杂度分析:

  • 时间复杂度:O(3^m×4^n),其中 m 是输入中对应 3 个字母的数字个数,n 是输入中对应 4 个字母的数字个数。不同的字母组合一共有3^m×4^n 种,需要遍历每一种字母组合。
  • 空间复杂度:O(m+n)。即为递归调用的最大层数。

参考