Example 1
ready- Input
digits = "23"- Expected
[ "ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf" ]- Why
- three choices from 2 combine with three choices from 3
One short number can hide a surprising number of words. The digits 23, for example,
can start with any letter on 2 and finish with any letter on 3.
Given a string digits, return every letter string it can spell on this phone keypad:
2 → abc, 3 → def, 4 → ghi, 5 → jkl6 → mno, 7 → pqrs, 8 → tuv, 9 → wxyzChoose exactly one letter for each digit, and keep the digit order. You may return the
finished strings in any order. When digits is empty, return [].
0 <= digits.length <= 7digits is one of 2 through 9.Hints
Start with the choices for the first digit. For each later digit, append each of its letters to every partial string you already have.
At position i, your only decision is which letter mapped from digits[i] comes
next. Once you choose it, move to position i + 1.
Add one letter to the current path, explore everything below that choice, then remove
it before trying the next letter. The empty input needs an early return so it produces
[], not a list containing one empty string.
Could you write the search so it stores only the current path, apart from the strings that must be returned?
Visible cases
digits = "23"[
"ad",
"ae",
"af",
"bd",
"be",
"bf",
"cd",
"ce",
"cf"
]digits = ""[]digits = "7"[
"p",
"q",
"r",
"s"
]Interview signal
A Cartesian product combines every choice from one group with every choice from the next. Keep a list of partial strings, then expand it once per digit.
def letter_combinations(digits: str) -> list[str]:
if not digits:
return []
keypad = {
"2": "abc", "3": "def", "4": "ghi", "5": "jkl",
"6": "mno", "7": "pqrs", "8": "tuv", "9": "wxyz",
}
combinations = [""]
for digit in digits:
next_combinations = []
for prefix in combinations:
for letter in keypad[digit]:
next_combinations.append(prefix + letter)
combinations = next_combinations
return combinationsIf every digit offers four letters, the answer contains 4ⁿ strings, each of length
n. Time O(4ⁿ · n), space O(4ⁿ · n), including the returned strings.
This is the backtracking pattern: make one choice, explore everything that follows,
then undo the choice before trying its neighbor. A list named path holds only the
letters chosen for the current candidate.
def letter_combinations(digits: str) -> list[str]:
if not digits:
return []
keypad = {
"2": "abc", "3": "def", "4": "ghi", "5": "jkl",
"6": "mno", "7": "pqrs", "8": "tuv", "9": "wxyz",
}
result: list[str] = []
path: list[str] = []
def search(index: int) -> None:
if index == len(digits):
result.append("".join(path))
return
for letter in keypad[digits[index]]:
path.append(letter)
search(index + 1)
path.pop()
search(0)
return resultEvery leaf is one answer, and joining its n letters costs O(n). Time O(4ⁿ · n) in
the worst case. Space O(n) auxiliary for the path and call stack, excluding the
required output.
The win isn't a smaller output—you must produce every string. Backtracking gives the search a clean shape while keeping unfinished candidates out of a growing table.
Ready to run.
3 cases are queued.
Visible testcase
Case 1
Expected
[ "ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf" ]