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.
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
- Check if
n < 4. If so, return 0, because no string shorter than 4 can contain"leet". - Precompute factorials and modular inverses up to
nmodulo 10^9 + 7. This allows us to compute combinations efficiently. - Identify that the minimum letter requirements for
"leet"are'l':1, 'e':2, 't':1. - The remaining
n-4letters can be any of the 26 lowercase letters. Since these letters do not affect the minimal requirement, there are26^(n-4)ways to fill the remaining positions. - Count the number of permutations of
"leet"itself, which is4! / (2!) = 12. This accounts for the repeated'e'. - Multiply the number of permutations of
"leet"by the number of ways to fill remaining positions, all modulo 10^9 + 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
- Strings shorter than 4: Any
n < 4cannot accommodate the substring"leet". Returning 0 prevents incorrect counting. - Large
nvalues:nup to 10^5 could cause overflow if factorials were naively computed. Using modular exponentiation avoids this. - Repeated letters in
"leet":'e'appears twice. Properly counting permutations with repeated letters ensures accurate results and avoids overcounting. In Python we usedfactorial(4)//factorial(2)and in Go we hardcoded 12.