LeetCode 2930 - Number of Strings Which Can Be Rearranged to Contain Substring

The problem asks us to count how many strings of length n made of lowercase English letters can be rearranged to contain the substring "leet". In other words, a string is "good" if, after any permutation of its characters, "leet" appears as a contiguous sequence.

LeetCode Problem 2930

Difficulty: 🟡 Medium
Topics: Math, Dynamic Programming, Combinatorics

Solution

Problem Understanding

The problem asks us to count how many strings of length n made of lowercase English letters can be rearranged to contain the substring "leet". In other words, a string is "good" if, after any permutation of its characters, "leet" appears as a contiguous sequence.

The input is a single integer n (1 ≤ n ≤ 10^5), representing the length of the string. The output is the total number of good strings modulo 10^9 + 7.

Important observations include: the string "leet" itself has 4 letters, so any good string must have at least length 4. The string "leet" has character counts: 'l':1, 'e':2, 't':1. Therefore, for a string of length n to be rearranged into something containing "leet", it must have at least these counts of letters 'l', 'e', and 't'. The remaining n-4 characters can be any lowercase letters.

Edge cases to consider include n < 4 where no string can possibly be good, and n = 4 where the answer is simply the number of unique permutations of "leet".

Approaches

The brute-force approach would involve generating all 26^n strings of length n, checking if any permutation contains "leet". While this is correct in principle, it is computationally infeasible for n up to 10^5.

The key insight for an optimal solution is combinatorics. Since a string must have at least 'l':1, 'e':2, 't':1, we can treat the problem as choosing positions for these letters in a length n string and filling the remaining positions with any letters. This reduces to a combinatorial counting problem with modulo arithmetic. Factorials, modular inverses, and exponentiation will be used to handle large numbers efficiently.

Approach Time Complexity Space Complexity Notes
Brute Force O(26^n * n!) O(n) Generate all strings and check permutations, impractical for n > 10
Optimal O(n) O(n) Use combinatorial counting with factorials and modular arithmetic

Algorithm Walkthrough

  1. Check if n < 4. If so, return 0, because no string shorter than 4 can contain "leet".
  2. Precompute factorials and modular inverses up to n modulo 10^9 + 7. This allows us to compute combinations efficiently.
  3. Identify that the minimum letter requirements for "leet" are 'l':1, 'e':2, 't':1.
  4. The remaining n-4 letters can be any of the 26 lowercase letters. Since these letters do not affect the minimal requirement, there are 26^(n-4) ways to fill the remaining positions.
  5. Count the number of permutations of "leet" itself, which is 4! / (2!) = 12. This accounts for the repeated 'e'.
  6. Multiply the number of permutations of "leet" by the number of ways to fill remaining positions, all modulo 10^9 + 7.
  7. Return the result.

Why it works: By ensuring the string contains at least the required letters and counting all ways to fill the remaining letters, we guarantee that all counted strings are "good". The formula accounts for duplicate letters correctly using factorial division.

Python Solution

class Solution:
    MOD = 10**9 + 7
    
    def stringCount(self, n: int) -> int:
        if n < 4:
            return 0
        
        # Number of ways to fill remaining n-4 letters
        remaining_ways = pow(26, n - 4, self.MOD)
        
        # Number of unique permutations of "leet" itself
        from math import factorial
        leet_perms = factorial(4) // factorial(2)  # 4! / 2! = 12
        
        return (leet_perms * remaining_ways) % self.MOD

Explanation: We handle n < 4 first. Then we calculate 26^(n-4) using Python's efficient pow with modulus. We compute permutations of "leet" considering the repeated 'e'. Finally, we multiply these counts and take modulo 10^9 + 7.

Go Solution

package main

func powMod(a, b, mod int) int {
    result := 1
    a = a % mod
    for b > 0 {
        if b%2 == 1 {
            result = (result * a) % mod
        }
        a = (a * a) % mod
        b /= 2
    }
    return result
}

func stringCount(n int) int {
    const MOD = 1000000007
    if n < 4 {
        return 0
    }
    
    remainingWays := powMod(26, n-4, MOD)
    
    // Number of permutations of "leet" (4! / 2! = 12)
    leetPerms := 12
    
    return (leetPerms * remainingWays) % MOD
}

Explanation: Go requires a custom modular exponentiation function. Factorials are simple for "leet", so we hardcode 12. Multiplication and modulo yield the final result.

Worked Examples

Example 1: n = 4

Remaining letters: 0

26^0 = 1

Permutations of "leet": 12

Answer = 12 * 1 = 12

Example 2: n = 10

Remaining letters: 6

26^6 = 308915776

Permutations of "leet": 12

Answer = 308915776 * 12 = 3706989312

Modulo 10^9 + 7 → 83943898

Complexity Analysis

Measure Complexity Explanation
Time O(1) Only a few mathematical operations and modular exponentiation are performed
Space O(1) No extra data structures proportional to n are needed

The modular exponentiation runs in O(log n) if implemented using repeated squaring. This is negligible for n ≤ 10^5.

Test Cases

# Example cases
assert Solution().stringCount(4) == 12  # minimal length string
assert Solution().stringCount(10) == 83943898  # larger string

# Edge cases
assert Solution().stringCount(1) == 0  # too short to contain "leet"
assert Solution().stringCount(3) == 0  # too short to contain "leet"
assert Solution().stringCount(5) == (12 * 26) % (10**9 + 7)  # one extra letter
assert Solution().stringCount(6) == (12 * 26**2 % (10**9 + 7))  # two extra letters
Test Why
n=4 Smallest valid string, verifies permutations of "leet"
n=10 Larger string, checks modulo correctness
n=1,3 Strings shorter than 4, should return 0
n=5,6 Small strings greater than 4, verifies extra letters counted correctly

Edge Cases

  1. Strings shorter than 4: Any n < 4 cannot accommodate the substring "leet". Returning 0 prevents incorrect counting.
  2. Large n values: n up to 10^5 could cause overflow if factorials were naively computed. Using modular exponentiation avoids this.
  3. Repeated letters in "leet": 'e' appears twice. Properly counting permutations with repeated letters ensures accurate results and avoids overcounting. In Python we used factorial(4)//factorial(2) and in Go we hardcoded 12.