Mutating counts without cleanup
Wrong move: Zero-count keys stay in map and break distinct/count constraints.
Usually fails on: Window/map size checks are consistently off by one.
Fix: Delete keys when count reaches zero.
Break down a hard problem into reliable checkpoints, edge-case handling, and complexity trade-offs.
You are given a string s and a positive integer k.
Let vowels and consonants be the number of vowels and consonants in a string.
A string is beautiful if:
vowels == consonants.(vowels * consonants) % k == 0, in other terms the multiplication of vowels and consonants is divisible by k.Return the number of non-empty beautiful substrings in the given string s.
A substring is a contiguous sequence of characters in a string.
Vowel letters in English are 'a', 'e', 'i', 'o', and 'u'.
Consonant letters in English are every letter except vowels.
Example 1:
Input: s = "baeyh", k = 2 Output: 2 Explanation: There are 2 beautiful substrings in the given string. - Substring "baeyh", vowels = 2 (["a",e"]), consonants = 2 (["y","h"]). You can see that string "aeyh" is beautiful as vowels == consonants and vowels * consonants % k == 0. - Substring "baeyh", vowels = 2 (["a",e"]), consonants = 2 (["b","y"]). You can see that string "baey" is beautiful as vowels == consonants and vowels * consonants % k == 0. It can be shown that there are only 2 beautiful substrings in the given string.
Example 2:
Input: s = "abba", k = 1 Output: 3 Explanation: There are 3 beautiful substrings in the given string. - Substring "abba", vowels = 1 (["a"]), consonants = 1 (["b"]). - Substring "abba", vowels = 1 (["a"]), consonants = 1 (["b"]). - Substring "abba", vowels = 2 (["a","a"]), consonants = 2 (["b","b"]). It can be shown that there are only 3 beautiful substrings in the given string.
Example 3:
Input: s = "bcdf", k = 1 Output: 0 Explanation: There are no beautiful substrings in the given string.
Constraints:
1 <= s.length <= 5 * 1041 <= k <= 1000s consists of only English lowercase letters.Problem summary: You are given a string s and a positive integer k. Let vowels and consonants be the number of vowels and consonants in a string. A string is beautiful if: vowels == consonants. (vowels * consonants) % k == 0, in other terms the multiplication of vowels and consonants is divisible by k. Return the number of non-empty beautiful substrings in the given string s. A substring is a contiguous sequence of characters in a string. Vowel letters in English are 'a', 'e', 'i', 'o', and 'u'. Consonant letters in English are every letter except vowels.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Hash Map · Math
"baeyh" 2
"abba" 1
"bcdf" 1
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #2949: Count Beautiful Substrings II
class Solution {
// Same as 2947. Count Beautiful Substrings I
public int beautifulSubstrings(String s, int k) {
final int root = getRoot(k);
int ans = 0;
int vowels = 0;
int vowelsMinusConsonants = 0;
// {(vowels, vowelsMinusConsonants): count}
Map<Pair<Integer, Integer>, Integer> prefixCount = new HashMap<>();
prefixCount.put(new Pair<>(0, 0), 1);
for (final char c : s.toCharArray()) {
if (isVowel(c)) {
vowels = (vowels + 1) % root;
++vowelsMinusConsonants;
} else {
--vowelsMinusConsonants;
}
Pair<Integer, Integer> prefix = new Pair<>(vowels, vowelsMinusConsonants);
ans += prefixCount.getOrDefault(prefix, 0);
prefixCount.merge(prefix, 1, Integer::sum);
}
return ans;
}
private boolean isVowel(char c) {
return "aeiou".indexOf(c) != -1;
}
private int getRoot(int k) {
for (int i = 1; i <= k; ++i)
if (i * i % k == 0)
return i;
throw new IllegalArgumentException();
}
}
// Accepted solution for LeetCode #2949: Count Beautiful Substrings II
package main
// https://space.bilibili.com/206214
func pSqrt(n int) int {
res := 1
for i := 2; i*i <= n; i++ {
i2 := i * i
for n%i2 == 0 {
res *= i
n /= i2
}
if n%i == 0 {
res *= i
n /= i
}
}
if n > 1 {
res *= n
}
return res
}
func beautifulSubstrings(s string, k int) (ans int64) {
k = pSqrt(k * 4)
type pair struct{ i, sum int }
cnt := map[pair]int{{k - 1, 0}: 1} // k-1 和 -1 同余
sum := 0
const aeiouMask = 1065233
for i, c := range s {
bit := aeiouMask >> (c - 'a') & 1
sum += bit*2 - 1
p := pair{i % k, sum}
ans += int64(cnt[p])
cnt[p]++
}
return
}
# Accepted solution for LeetCode #2949: Count Beautiful Substrings II
class Solution:
# Same as 2947. Count Beautiful Substrings I
def beautifulSubstrings(self, s: str, k: int) -> int:
VOWELS = 'aeiou'
root = self._getRoot(k)
ans = 0
vowels = 0
vowelsMinusConsonants = 0
# {(vowels, vowelsMinusConsonants): count}
prefixCount = collections.Counter({(0, 0): 1})
for c in s:
if c in VOWELS:
vowelsMinusConsonants += 1
vowels = (vowels + 1) % root
else:
vowelsMinusConsonants -= 1
ans += prefixCount[(vowels, vowelsMinusConsonants)]
prefixCount[(vowels, vowelsMinusConsonants)] += 1
return ans
def _getRoot(self, k: int) -> int:
for i in range(1, k + 1):
if i * i % k == 0:
return i
// Accepted solution for LeetCode #2949: Count Beautiful Substrings II
// Rust example auto-generated from java reference.
// Replace the signature and local types with the exact LeetCode harness for this problem.
impl Solution {
pub fn rust_example() {
// Port the logic from the reference block below.
}
}
// Reference (java):
// // Accepted solution for LeetCode #2949: Count Beautiful Substrings II
// class Solution {
// // Same as 2947. Count Beautiful Substrings I
// public int beautifulSubstrings(String s, int k) {
// final int root = getRoot(k);
// int ans = 0;
// int vowels = 0;
// int vowelsMinusConsonants = 0;
// // {(vowels, vowelsMinusConsonants): count}
// Map<Pair<Integer, Integer>, Integer> prefixCount = new HashMap<>();
// prefixCount.put(new Pair<>(0, 0), 1);
//
// for (final char c : s.toCharArray()) {
// if (isVowel(c)) {
// vowels = (vowels + 1) % root;
// ++vowelsMinusConsonants;
// } else {
// --vowelsMinusConsonants;
// }
// Pair<Integer, Integer> prefix = new Pair<>(vowels, vowelsMinusConsonants);
// ans += prefixCount.getOrDefault(prefix, 0);
// prefixCount.merge(prefix, 1, Integer::sum);
// }
//
// return ans;
// }
//
// private boolean isVowel(char c) {
// return "aeiou".indexOf(c) != -1;
// }
//
// private int getRoot(int k) {
// for (int i = 1; i <= k; ++i)
// if (i * i % k == 0)
// return i;
// throw new IllegalArgumentException();
// }
// }
// Accepted solution for LeetCode #2949: Count Beautiful Substrings II
function beautifulSubstrings(s: string, k: number): number {
const l = pSqrt(k * 4);
const n = s.length;
let sum = n;
let ans = 0;
const counter = new Map();
counter.set(((l - 1) << 17) | sum, 1);
for (let i = 0; i < n; i++) {
const char = s[i];
const bit = (AEIOU_MASK >> (char.charCodeAt(0) - 'a'.charCodeAt(0))) & 1;
sum += bit * 2 - 1; // 1 -> 1 0 -> -1
const key = ((i % l) << 17) | sum;
ans += counter.get(key) || 0; // ans += cnt[(i%k,sum)]++
counter.set(key, (counter.get(key) ?? 0) + 1);
}
return ans;
}
const AEIOU_MASK = 1065233;
function pSqrt(n: number) {
let res = 1;
for (let i = 2; i * i <= n; i++) {
let i2 = i * i;
while (n % i2 == 0) {
res *= i;
n /= i2;
}
if (n % i == 0) {
res *= i;
n /= i;
}
}
if (n > 1) {
res *= n;
}
return res;
}
Use this to step through a reusable interview workflow for this problem.
For each element, scan the rest of the array looking for a match. Two nested loops give n × (n−1)/2 comparisons = O(n²). No extra space since we only use loop indices.
One pass through the input, performing O(1) hash map lookups and insertions at each step. The hash map may store up to n entries in the worst case. This is the classic space-for-time tradeoff: O(n) extra memory eliminates an inner loop.
Review these before coding to avoid predictable interview regressions.
Wrong move: Zero-count keys stay in map and break distinct/count constraints.
Usually fails on: Window/map size checks are consistently off by one.
Fix: Delete keys when count reaches zero.
Wrong move: Temporary multiplications exceed integer bounds.
Usually fails on: Large inputs wrap around unexpectedly.
Fix: Use wider types, modular arithmetic, or rearranged operations.