Problem Statement

Letter Combinations of a Phone Number

Think of an old phone keypad. Each number key (2 through 9) has a few letters printed on it. Key 2 is "abc", key 3 is "def", and so on. You are given a string of digits like "23". Your job is to list every word you could spell by picking one letter from each key, in order. For "23" you pick one letter from key 2 (a, b, or c) and one letter from key 3 (d, e, or f). Return all of those combinations in any order. If the input is empty, return an empty list.

mediumBacktrackingBacktrackingTime: O(4^n * n) · Space: O(n)

Signals to notice

map digits to lettersgenerate all possible stringscombinatorial explosion

Brute force first

Not applicable — generating all combinations IS the problem. Output size is up to 4^n. That direct path helps you understand the question, but it tends to treat every possibility as brand new instead of learning from earlier steps.

The key insight

Backtracking: for each digit, try each possible letter mapping. Build the string character by character. When the string reaches input length, record it. The goal is not to be clever for its own sake, but to remember the one relationship that keeps the solution grounded as you move forward.

Trace it on digits="23" (phone: 2->abc, 3->def)

digits non-empty -> call backtrack(idx=0, current=""); result=[]
idx=0, digit '2'->"abc": loop letter 'a' -> backtrack(1, "a")
  idx=1, digit '3'->"def": 'd'->backtrack(2,"ad") idx==len -> result=["ad"]; 'e'->"ae"; 'f'->"af" -> result=["ad","ae","af"]
back at idx=0, letter 'b' -> backtrack(1, "b") -> appends "bd","be","bf" -> result=[..,"bd","be","bf"]
back at idx=0, letter 'c' -> backtrack(1, "c") -> appends "cd","ce","cf" -> result has 9 strings
idx=0 loop done, recursion unwinds; return result
answer = ["ad","ae","af","bd","be","bf","cd","ce","cf"]

What must stay true

Each digit maps to 3-4 letters. At each position, try all possible letters for the current digit, then recurse for the next digit. The branching factor is the number of letters per digit. If that remains true after every update, the rest of the reasoning has a stable place to stand.

Shape of the loop

function backtrack(idx, current):
    if idx == len(digits):        # built one full combination
        result.append(current); return
    for letter in phone[digits[idx]]:   # try each letter for this digit
        backtrack(idx + 1, current + letter)
# kick off: if digits: backtrack(0, "")

Pseudocode only — the full worked solution lives in the Solution tab.

Easy way to go wrong

Not handling the empty input case — return an empty array, not an array with an empty string. The fix is usually to return to the meaning of each move, not just the steps themselves.

Backtracking Pattern