电话号码的字母组合:循环遍历 + 递归 + 回溯

129 阅读1分钟

题目

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

思路

  • 暴力解法最多需要写四重循环时间复杂度太高,于是考虑空间换时间
    • 空间换时间,可以考虑1使用map存储,2使用递归
      • 递归遍历输入字符串的时候只需要对递归函数传入数字对应的索引,通过 索引+1 实现递归
      • 对给定输入字符串"2345",可以递归计算每一个数字,在递归每一个数字的时候,for循环遍历该数字代表的字符
    • 维护一个用来组合某一种可能性的组合(即数组),每次一条递归链条结束的时候,将将组合中的数据pop一个,即将组合数组进行清理,以便下次循环递归(回溯的时候再push新的数据)的时候使用。

image.png

代码

/**
 * @param {string} digits
 * @return {string[]}
 */
var letterCombinations = function(digits) {
     let n = digits.length;
            if (n === 0) return [];
            let map = {
                "2": "abc",
                "3": "def",
                "4": "ghi",
                "5": "jkl",
                "6": "mno",
                "7": "pqrs",
                "8": "tuv",
                "9": "wxyz",
            }
            let combinations = [];
            let combination = [];

            const backtrack = (index) => {
                if (index === n) {
                    combinations.push(combination.join(""));
                } else {
                    let digit = digits[index];
                    for (let key in map[digit]) {
                        if (map[digit].hasOwnProperty(key)) { // 确保只遍历自身的属性
                            combination.push(map[digit].charAt(key));
                            backtrack(index + 1)
                            combination.pop()
                        }

                    }
                }
            }

            backtrack(0);
            return combinations;
};