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.
Signals to notice
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.