← DSA Atlas
Dedicated problem page · #17

Letter Combinations of a Phone Number

MediumBacktrackingCartesian product of digit-letter groupsBacktracking over a fixed keypad mapping
Solve on LeetCode ↗
17
MediumBacktrackingBacktracking over a fixed keypad mappingCartesian product of digit-letter groups

Letter Combinations of a Phone Number

Given a string containing digits from 2 to 9, return all possible letter combinations that the number could spell on a classic phone keypad. Return the combinations in any order. An empty input string yields an empty list.

Open official problem prompt ↗
In plain English

Enumerate every string obtainable by replacing each digit with one of its keypad letters, one letter per digit.

Picture it like this

Old T9 texting: each number key hides several letters, and you want to list every word-shape you could type if you tapped each key once and picked any of its letters.

Example
Input
digits = "23"
Output
["ad","ae","af","bd","be","bf","cd","ce","cf"]
Why
Digit 2 maps to {a,b,c} and 3 maps to {d,e,f}; every pairing of one letter from each gives 3 x 3 = 9 strings.
Constraints
0 <= digits.length <= 4digits[i] is a digit in the range ['2', '9']
Pattern lesson

See the pattern, then code

Cartesian product of digit-letter groups
Recognition clue

Producing every combination formed by choosing one item from each of several fixed groups is a Cartesian product, naturally built with backtracking.

Backtracking

Generate every valid combination, permutation, partition, or configuration.. Process digits left to right. At depth i, branch once per letter that digits[i] maps to, appending it to the running string; when the string reaches the length of digits, it is one complete combination.

New words, made simpleKnow these before the algorithm
Cartesian product
All ordered tuples formed by taking one element from each of several sets.
Keypad mapping
The fixed dictionary from each digit 2-9 to its group of letters.
Depth = index
Recursion depth equals the digit position currently being assigned a letter.
Approaches from first idea to best ideaCompare the trade-offs
ApproachHow it thinksCost
Iterative queue expansion

Correct and loop-based, but holds all partial strings in memory at once; slightly more bookkeeping.

Start with [''] and for each digit replace the queue with every existing prefix extended by each mapped letter.

Time O(4^n * n)Space O(4^n * n)
The rule we keep true

Invariant

At the call for index i, path holds exactly i chosen letters, one for each digit processed so far, in order.

Why this is correct

Reasoning

Every leaf of the tree is reached by choosing one letter at each digit, which is precisely one element of the Cartesian product; because each digit's loop covers all its letters and depth advances by one per digit, every product tuple is produced once and only once.

The algorithm in three movesSay these aloud before coding
1Return [] immediately if digits is empty

i=0 pick 'a'

2Build the digit -> letters mapping

i=1 pick 'd' -> record 'ad'

3Recurse over digit index i, trying each mapped letter; when i equals len(digits), record the assembled string

backtrack -> 'ae', 'af', ...

Visual trace

Follow the data, one decision at a time

Input snapshotHighlighted cells are involved in this example
2->abc0
3->def1
1 · Readdigits='23'
2 · AskEmpty input?
3 · Update stateres=[]
4 · ResultNot empty; proceed to backtrack(0)
Key takeaway

A two-level tree: three branches for digit 2, each splitting into three for digit 3.

Code walkthrough

Read the solution in small chunks

Python 3

Do not memorize the whole program. Connect each group of lines to one job in the algorithm.

  1. 1
    Lines 3-4Empty guard

    An empty digits string has zero combinations, so return [] before doing any work.

  2. 2
    Lines 5-8Keypad mapping

    A dictionary encodes the fixed digit-to-letters relationship used at each level.

  3. 3
    Lines 13-19Per-digit branching

    At index i, loop over every mapped letter, push it, recurse to the next digit, then pop; when i hits the end, join path into a finished string.

Make it stick

Edge cases, mistakes, and one self-check

E

Edge cases to test

  • Empty string returns [] (not [''])
  • Single digit like '7' returns all four of p,q,r,s
  • Digits containing 7 or 9 branch four ways, raising the count
!

Common beginner mistakes

  • Returning [''] instead of [] for empty input
  • Hardcoding three letters per digit and mishandling 7 (pqrs) and 9 (wxyz)
  • Building strings by concatenation in a way that mutates shared state without restoring it
Check your understanding

Why is the empty-input case handled specially rather than falling out of the recursion?