電話號碼的組合
公式運算、笛卡爾積
1.題目
給定一個僅包含數字 2-9 的字符串,返回所有它能表示的字母組合。
給出數字到字母的映射如下(與電話按鍵相同)。注意 1 不對應任何字母。
示例:
輸入:“23”
輸出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
說明:儘管上面的答案是按字典序排列的,但是你可以任意選擇答案輸出的順序。
2.思路分析
3.所用到的方法
Array.prototype.splice(index, num, new Arrray)
- index:需要刪除元素的起始位置
- num:需要刪除元素的數量
- new Arrray:向被刪除元素的位置添加的新項目
- 方法體返回包含被刪除的元素的數組
4.題解及優化
我的初始解法
var letterCombinations = function (digits) {
// 鍵盤映射
let all = ['', '', 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']
// 初始化選中的
let list = []
let result = []
for (let i = 0; i < digits.length; i++) {
// 拿到選中的
list = list.concat(all[digits.split('')[i]])
// 每一項拆分爲單個字符
list[i] = list[i].split('')
}
// 處理邊緣極小值
if (digits.length < 1) return list
if (digits.length < 2) return list[0]
// 組合運算
function mix (a, b) {
for (let i = 0; i < a.length; i++) {
for (let j = 0; j < b.length; j++) {
result = result.concat(a[i] + b[j])
}
}
}
for (let i = 0; i < digits.length - 1; i++) {
// 前兩項進行組合運算
mix(list[0], list[1])
// 將處理過的元素刪掉
list.splice(0, 2)
// 將處理的結果填入(按照規則必須填入首位),參與下一次處理
list.unshift(result)
}
// 返回篩選合格的元素
return result.filter(item => item.length === digits.length)
}
第一次優化
var letterCombinations = function (digits) {
// 鍵盤映射
let all = ['', '', 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']
// 初始化選中的
let list = []
let result = []
for (let i = 0; i < digits.length; i++) {
// 拿到選中的,並將每一項拆分爲單個字符
list.push(all[digits.split('')[i]].split(''))
}
// 處理邊緣極小值
if (digits.length < 1) return list
if (digits.length < 2) return list[0]
for (let i = 0; i < digits.length - 1; i++) {
// 前兩項進行組合運算
for (let j = 0; j < list[0].length; j++) {
for (let k = 0; k < list[1].length; k++) {
result = result.concat(list[0][j] + list[1][k])
}
}
// 將處理過的元素刪掉, 並將處理的結果填入(按照規則必須填入首位),參與下一次處理
list.splice(0, 2, result)
}
// 返回篩選合格的元素
return result.filter(item => item.length === digits.length)
}
由於思維固化,暫時找不到優化方案了(可以結構優化,但性能並沒有優化)
課程解法
使用了遞歸
var letterCombinations = function (digits) {
// 對輸入做處理,如果小於1返回空(LeetCode測試用例)
if (digits.length < 1) return []
// 建立電話號碼鍵盤映射
let map = ['', 1, 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']
// 如果只給了一個按鍵,直接把按鍵內容取出來並按單個字符分組就可以了(LeetCode測試用例)
if (digits.length < 2) return map[digits].split('')
// 把輸入字符串按單字符分隔變成數組,234=>[2,3,4]
let num = digits.split('')
// 保存鍵盤映射後的字母內容,如 23=>['abc','def']
let code = []
num.forEach(item => {
if (map[item]) {
code.push(map[item])
}
})
let comb = (arr) => {
// 臨時變量用來保存前兩個組合的結果
let tmp = []
// 最外層的循環是遍歷第一個元素,裏層的循環是遍歷第二個元素
for (let i = 0, il = arr[0].length; i < il; i++) {
for (let j = 0, jl = arr[1].length; j < jl; j++) {
tmp.push(`${arr[0][i]}${arr[1][j]}`)
}
}
arr.splice(0, 2, tmp)
if (arr.length > 1) {
comb(arr)
} else {
return tmp
}
return arr[0]
}
return comb(code)
}
其他小夥伴的解法
最簡解法
var letterCombinations = function(digits) {
if (!digits) return []
const strMap = ['', '', 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']
return digits.split('').reduce((result, num) => result.flatMap(t => strMap[num].split('').map(s => t + s)), [''])
}
解法1
var letterCombinations = function (digits) {
if (!digits) { return [] }
const strMap = ['', '', 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']
let result = [''] // 初始化一個空字符,方便後續遍歷
for (let num of digits) { // 遍歷輸入的數字
let nextResult = []
let str = strMap[num] // 找到數字可能對應的字符
for (let t of result) { // 遍歷上一循環生成的字符串列表
for (let s of str) { // 遍歷當前數字可能對應的字符
nextResult.push(t + s) // 拼接字符串
}
}
result = nextResult // 替換原字符串列表
}
return result
}
解法2:使用Object
var letterCombinations = function(digits) {
const maps = {
2: 'abc',
3: 'def',
4: 'ghi',
5: 'jkl',
6: 'mno',
7: 'pqrs',
8: 'tuv',
9: 'wxyz'
}
const res = []
for (let num of digits) {
let w = maps[num]
if (res.length > 0) {
let tmp = []
for (let i = 0; i < res.length; i++) {
let wl = w.length
for (let j = 1; j < wl; j++) {
tmp.push(res[i] + w[j])
}
res[i] += w[0]
}
res.push(...tmp)
} else {
res.push(...w)
}
}
return res
}
解法3:使用Map
var letterCombinations = function (digits) {
if (!digits) return []
let len = digits.length
let map = new Map()
map.set('2', 'abc')
map.set('3', 'def')
map.set('4', 'ghi')
map.set('5', 'jkl')
map.set('6', 'mno')
map.set('7', 'pqrs')
map.set('8', 'tuv')
map.set('9', 'wxyz')
let result = []
function _generate (i, str) {
if (i === len) {
result.push(str)
return
}
let tmp = map.get(digits[i])
for (let r = 0; r < tmp.length; r++) {
_generate(i + 1, str + tmp[r])
}
}
_generate(0, '')
return result
}
拓展: