LeetCode系列记录我学习算法的过程。
持续创作,加速成长!这是我参与「掘金日新计划 6 月更文挑战」的第 16 天,点击查看活动详情
题目
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例:
输入: digits = "23"
输出: ["ad","ae","af","bd","be","bf","cd","ce","cf"]
输入: digits = ""
输出: []
输入: digits = "2"
输出: ["a","b","c"]
提示
0 <= digits.length <= 4digits[i]是范围['2', '9']的一个数字。
思路
这题可以通过通过多个循环来遍历所有的组合,但是传入的数字字符串长度不定,所以要采用其他的思路
通过给定的示例我们可以发现一些规律,每一个数字对应的字符不需要去与其他所有数字对应的字符进行组合
只需要跟前面数字已经处理好的组合进行遍历重组即可:
- 首先创建电话号码对应的字母映射
- 遍历传入的第一个数字对应的字符串,存入
res - 遍历第二个数字对应的字符串及
res,将所有组合结果覆盖res - 遍历第三个。。。
- 最后将结果返回即可
代码实现
/**
* @param {string} digits
* @return {string[]}
*/
var letterCombinations = function(digits) {
// 号码的映射
const map = {
'2': 'abc',
'3': 'def',
'4': 'ghi',
'5': 'jkl',
'6': 'mno',
'7': 'pqrs',
'8': 'tuv',
'9': 'wxyz'
}
// 答案
let res = []
// 遍历传入的字符串
for(let d of digits) {
// res有内容则遍历res及当前字符的组合
if(res.length) {
let temp = [] // 暂时存储结果
// 遍历 res
for(let r of res) {
// 遍历当前数字对应的 字符串
for(let s of map[d]) {
// 将组合结果存入temp
temp.push(r + s)
}
}
// 覆盖 res
res = temp
} else {
// 否则直接遍历当前字符对应的字母
for(let s of map[d]) {
res.push(s)
}
}
}
return res
};
优化
还有一种很巧妙的利用递归来解题的方法
/**
* @param {string} digits
* @return {string[]}
*/
var letterCombinations = function(digits) {
if (digits.length == 0) return [];
const res = [];
// 号码的映射
const map = {
2: "abc",
3: "def",
4: "ghi",
5: "jkl",
6: "mno",
7: "pqrs",
8: "tuv",
9: "wxyz",
};
const dfs = (curStr, i) => {
// 结束条件 达到边界
if (i > digits.length - 1) {
// 将结果存入 res
res.push(curStr);
return;
}
// 遍历当前数字对应的字符串
const letters = map[digits[i]];
for (const l of letters) {
// 递归,传入字符组合 及 下一下标
dfs(curStr + l, i + 1);
}
};
dfs("", 0);
return res;
};