一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第22天,点击查看活动详情。
题目
给定一个仅包含数字 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 <= 4digits[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)。即为递归调用的最大层数。