【筆記】JavaScript版數據結構與算法——基礎算法之“數組類”(17. 電話號碼的字母組合)


電話號碼的組合

公式運算、笛卡爾積

1.題目

17. 電話號碼的字母組合 - 力扣(LeetCode)

給定一個僅包含數字 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
}

在這裏插入圖片描述

拓展:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章