Letter Combinations of a Phone Number

Medium
9 views
10 years ago

We're going to work on a problem called "Letter Combinations of a Phone Number".

The problem is as follows: Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent. Return the answer in any order.

A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.

2 -> "abc" 3 -> "def" 4 -> "ghi" 5 -> "jkl" 6 -> "mno" 7 -> "pqrs" 8 -> "tuv" 9 -> "wxyz"

So, you need to write a function that takes a string of digits as input and returns a list of strings, where each string is a possible letter combination. Here are some examples:

  • Example 1:

    • Input: digits = "23"
    • Output: ["ad","ae","af","bd","be","bf","cd","ce","cf"]
  • Example 2:

    • Input: digits = ""
    • Output: []
  • Example 3:

    • Input: digits = "2"
    • Output: ["a","b","c"]

Can you describe your approach to solving this problem?

Sample Answer

Letter Combinations of a Phone Number

Let's break down the problem of generating letter combinations from a phone number. I'll start with a naive approach, then move to an optimized one, covering complexities, edge cases, and code.

Problem Description

Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent. Return the answer in any order.

A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.

2: abc 3: def 4: ghi 5: jkl 6: mno 7: pqrs 8: tuv 9: wxyz

1. Naive/Brute Force Approach

A brute-force approach would involve generating all possible combinations by iterating through the letters corresponding to each digit and concatenating them. This would involve nested loops or recursion.

Let's say the input is "23". We would iterate through 'a', 'b', 'c' for '2' and for each of those, iterate through 'd', 'e', 'f' for '3'.

This is conceptually simple, but not always the most efficient, especially for longer digit strings.

2. Optimal Solution: Backtracking

The optimal solution typically involves a backtracking algorithm. Backtracking systematically explores all possible solutions by trying every potential candidate. If a candidate leads to a dead end, we backtrack (undo the last choice) and try a different candidate.

Here's the general algorithm:

  1. Mapping: Create a mapping from digits to their corresponding letters (e.g., '2' -> "abc").
  2. Recursive Function: Define a recursive function (e.g., backtrack(combination, next_digits)) that takes the current combination and the remaining digits as input.
  3. Base Case: If there are no more digits to process (next_digits is empty), add the current combination to the list of results.
  4. Recursive Step:
    • Get the letters corresponding to the first digit in next_digits.
    • Iterate through each letter.
    • Recursively call backtrack with the updated combination (adding the current letter) and the remaining digits (removing the first digit).

3. Big O Run-time

  • Time Complexity: O(4N), where N is the length of the input digit string. In the worst case, each digit maps to 4 letters (e.g., '7' or '9'). We explore all possible combinations.

4. Big O Space Usage

  • Space Complexity: O(N), where N is the length of the input digit string. This is primarily due to the call stack during the recursive calls. In addition, the space to store the output result depends on the number of generated combinations, which can be O(4N) in the worst case. However, for the purpose of auxiliary space, we consider only O(N) used by the recursion depth.

5. Edge Cases

  • Empty Input: If the input digit string is empty, return an empty list.
  • Input Containing '1' or '0': These digits don't map to letters in the given problem, so we should likely ignore them, or return an empty list if all digits are invalid.
  • Invalid Characters: Handle cases where the input string contains characters other than digits 2-9. You might want to throw an exception or filter the input.

6. Code (Python)

python def letterCombinations(digits: str) -> list[str]: if not digits: return []

digit_to_letters = {
    '2': 'abc',
    '3': 'def',
    '4': 'ghi',
    '5': 'jkl',
    '6': 'mno',
    '7': 'pqrs',
    '8': 'tuv',
    '9': 'wxyz'
}

combinations = []

def backtrack(combination, next_digits):
    if not next_digits:
        combinations.append(combination)
        return

    digit = next_digits[0]
    letters = digit_to_letters[digit]
    for letter in letters:
        backtrack(combination + letter, next_digits[1:])

backtrack("", digits)
return combinations

Explanation of the Code

  1. digit_to_letters: A dictionary maps digits to their corresponding letters.
  2. combinations: A list to store the resulting combinations.
  3. backtrack(combination, next_digits):
    • Base Case: If next_digits is empty, it means we have processed all digits, so we add the current combination to the combinations list.
    • Recursive Step: We get the letters corresponding to the first digit in next_digits. We then iterate through each letter and recursively call backtrack with the updated combination and the remaining digits.
  4. The function returns the list of combinations.

Example

For the input "23", the function would return: ['ad', 'ae', 'af', 'bd', 'be', 'bf', 'cd', 'ce', 'cf']