{x}
blog image

Letter Case Permutation

Given a string s, you can transform every letter individually to be lowercase or uppercase to create another string.

Return a list of all possible strings we could create. Return the output in any order.

 

Example 1:

Input: s = "a1b2"
Output: ["a1b2","a1B2","A1b2","A1B2"]

Example 2:

Input: s = "3z4"
Output: ["3z4","3Z4"]

 

Constraints:

  • 1 <= s.length <= 12
  • s consists of lowercase English letters, uppercase English letters, and digits.

Solution Explanation

This problem asks to generate all possible letter case permutations of a given string. The string can contain lowercase letters, uppercase letters, and digits. We need to generate all combinations where each letter can be either uppercase or lowercase.

Two approaches are presented below:

Approach 1: Backtracking

This approach uses a depth-first search (DFS) to explore all possible combinations. The core idea is to recursively process each character:

  1. Base Case: If we've processed all characters (reached the end of the string), add the current permutation to the result.

  2. Recursive Step:

    • Recursively call the function to process the next character without changing its case.
    • If the current character is a letter:
      • Change its case (toggle between uppercase and lowercase).
      • Recursively call the function to process the next character with the changed case.

Time Complexity Analysis:

  • Let n be the length of the input string s.
  • Let k be the number of letters in the string.
  • The algorithm explores 2k possible combinations.
  • Each combination involves creating a string (which takes O(n) time in the worst case).
  • Therefore, the overall time complexity is O(n * 2k), where k is at most n. In the worst case where all characters are letters, the time complexity becomes O(n * 2n).

Space Complexity Analysis:

  • The space complexity is dominated by the recursive call stack and the list of resulting strings.
  • The maximum depth of the recursive call stack is n.
  • The size of the list of resulting strings is 2k, where k is the number of letters.
  • Thus, the overall space complexity is O(n + 2k), which can be simplified to O(2n) in the worst case.

Approach 2: Bit Manipulation

This approach leverages bit manipulation to generate all combinations. The idea is that for each letter, we have two choices (uppercase or lowercase). We can represent these choices using bits: 0 for lowercase and 1 for uppercase.

  1. Count Letters: First, count the number of letters (n) in the input string.

  2. Iterate Through Combinations: Iterate from 0 to 2n - 1. Each integer in this range represents a unique combination of uppercase/lowercase choices. We can use bitwise operations (& and >>) to determine the case for each letter.

  3. Generate String: For each combination, create a new string by converting the letters to uppercase or lowercase based on the bits.

Time Complexity Analysis:

  • The number of iterations is 2n, where n is the number of letters in the string.
  • Creating each string takes O(m) time, where m is the length of the string.
  • Therefore, the overall time complexity is O(m * 2n), where n is at most m. In the worst case it becomes O(n * 2n).

Space Complexity Analysis:

  • The space complexity is dominated by the list of resulting strings. This list has a size of 2n.
  • Thus, the space complexity is O(m * 2n), which is O(n * 2n) in the worst case.

Code Examples (Python, Java, C++, Go, TypeScript, Rust):

The provided code examples demonstrate both approaches in multiple languages. The backtracking approach is generally more concise and easier to understand, while the bit manipulation approach can be slightly faster for very large inputs because it avoids recursion. However, the asymptotic time complexity is the same for both. Choose the approach that best suits your understanding and coding style.