Description

給定一個包含 2-9 數字的字串,回傳所有該數字組合能代表的字母組合(按手機九宮格鍵盤的對應)。答案可以任意順序回傳。

Example:

Input: digits = “23” Output: [“ad”,“ae”,“af”,“bd”,“be”,“bf”,“cd”,“ce”,“cf”]

Intuition#

核心思路:每個數字對應 3-4 個字母,逐位數字展開所有可能的字母選擇,就是一棵回溯搜尋樹。

  • 建立數字到字母的映射表
  • 第一個數字有 3-4 種選擇,第二個數字也有 3-4 種選擇 …
  • 每層選一個字母,遞迴到下一個數字,直到所有數字都處理完

Approaches#

1: Iterative(BFS 風格)#

  • 概念: 逐個數字處理,對每個數字,將現有的所有組合各自擴展新字母
  • 時間複雜度: O(4^n * n) - n 為 digits 長度
  • 空間複雜度: O(4^n * n) - 存所有組合
class Solution {
    fun letterCombinations(digits: String): List<String> {
        if (digits.isEmpty()) return emptyList()

        val mapping = mapOf(
            '2' to "abc", '3' to "def", '4' to "ghi", '5' to "jkl",
            '6' to "mno", '7' to "pqrs", '8' to "tuv", '9' to "wxyz"
        )

        var result = listOf("")
        for (digit in digits) {
            val letters = mapping[digit]!!
            result = result.flatMap { combo ->
                letters.map { combo + it }
            }
        }
        return result
    }
}

⭐2: Backtracking#

  • 概念: 逐位數字選擇字母,遞迴到底就得到一個完整組合
  • 時間複雜度: O(4^n * n) - 最多 4^n 個組合
  • 空間複雜度: O(n) - 遞迴深度
class Solution {
    fun letterCombinations(digits: String): List<String> {
        if (digits.isEmpty()) return emptyList()

        val mapping = mapOf(
            '2' to "abc", '3' to "def", '4' to "ghi", '5' to "jkl",
            '6' to "mno", '7' to "pqrs", '8' to "tuv", '9' to "wxyz"
        )

        val result = mutableListOf<String>()
        val sb = StringBuilder()

        fun backtrack(index: Int) {
            if (index == digits.length) {
                result.add(sb.toString())
                return
            }

            val letters = mapping[digits[index]]!!
            for (letter in letters) {
                sb.append(letter)
                backtrack(index + 1)
                sb.deleteCharAt(sb.lastIndex)
            }
        }

        backtrack(0)
        return result
    }
}

🔑 Takeaways#

  • Pattern: 多層選擇展開 → 回溯法的基本應用,每層選擇來自不同的候選集
  • 關鍵技巧: 用 StringBuilder 比字串拼接更高效;映射表用 Map 或陣列都可以,陣列更快