JS算法之电话号码的字母组合

281 阅读1分钟

这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战

电话号码的字母组合

Hot100 17. 电话号码的字母组合

难度:中等

题目:leetcode-cn.com/problems/le…

给定一个仅包含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'] 的一个数字。

题解

刚开始可能发现使用暴力法来解,比如"23"时可以用两层for循环,但如果是"213",则需要三层for循环,可见,暴力法的方式不可取。

回溯法

回溯法可以用于解决n个for循环的问题。

思路:

  • 数字和字母映射,通过一个数组来将下标和字母映射起来。
  • 边界条件判定,当digits为空时,返回[],当digits长度为1时,返回其电话按键的字母。
  • 通过画图,我们可以很容易画出一棵多叉树,其叶子结点就是一对字母,利用数组path将其存储,而利用数组res存储path(需数组转字符串)。
  • 在递归过程中,若已经递归到底部,则停止递归,并将结果输出。
/**
 * @param {string} digits
 * @return {string[]}
 */
var letterCombinations = function(digits) {
  const depth = digits.length;
  const map = ['','','abc','def','ghi','jkl','mno','pqrs','tuv','wxyz'];
  if(!depth) return [];
  if(depth === 1) return map[digits].split('');
  
  const res = [], path = [];
  backtracking(digits, depth, 0);
  return res;
  
  // a用于控制digits的进位
  function backtracking(digits, depth, a) {
    // 当递归到最底层时,将每个递归结果存入res中
    if(path.length === depth){
      res.push(path.join('')); // 数组转字符串,如['a','b'] => 'ab'
      return;
    }
    for(const v of map[digits[a]]){
      path.push(v);
      backtracking(digits, depth, a+1);
      path.pop();
    }
  }
};

时间复杂度:O(3^m×4^n),其中 m 是输入中对应 3 个字母的数字个数(包括数字 2、3、4、5、6、8),n是输入中对应 4个字母的数字个数(包括数字 7、9)。

空间复杂度:O(m+n),m+n是输入数字的总个数。


坚持每日一练!前端小萌新一枚,希望能点个+在看哇~