My love for the sliding window is wavering. This is mainly due the number of edge cases this question has.
It makes perfect sense to use a sliding window for this problem, as we are trying to count the number of contiguous non-empty substrings.
However, there are a lot of conditions we need to satisfy, such as having to track the number of unique vowels and the number of consonants.
We do this with an integer array, letter_count[6], where letter_count[0] counts the consonants and letter_count[1] to letter_count[5] counts the vowels
Now, all there is to do is to address the main logic behind the algorithm,
- for a sliding window solution, we obviously need minimum 2 pointers,
landr1.
- intuitively, it makes sense that we should increment
r1until we have a valid substring
- this is because you can add more vowels to this sliding window to form more valid substrings
but how should we track all these subsequent valid substrings?
- this is where our 3rd pointer comes in
r2
- we initialise
r2 = r1, and continue to iterater2until it reaches a consonant (or the end ofword)
- this implies that all the indices between
r1andr2are vowels- then, as long as we know there exist
5unique vowels and number of consonants,letter_count[0], is equal tok,r2 - r1 + 1is equal to the total number of valid substrings beginning from index positionl
the next problem is that, since this is a sliding window solution, we have to increment l somehow:
- it makes intuitive sense that we should be incrementing
lafter we find all the possible valid substrings starting from indexl- if we increment, we have to make sure we remove
word[l]:
- if
word[l]is a consonant, then we can just stop iterating throughl
- we know that there are less than
kconsonants now, so we can start from the beginning and incrementr1instead- if
word[l]is a vowel:
- if there are no more
word[l]letters remaining inword:
- implies that there are only
4unique vowels now- we can increment
r1until we get either5unique vowels now or we reachr2- then we just add
r2-r1+1toansif we have5unique vowels- if there are more
word[l]letters remaining inword:
- we can simply just add
r2-r1+1toans
The main problem now, is that implementing this logic might be slightly difficult.
code
class Solution {
public:
long long countOfSubstrings(string word, int k) {
int l = 0;
int r1 = 0;
int r2 = 0;
int vowel_count = 0;
unordered_map<char, int> mp {{'a', 1}, {'e', 2}, {'i', 3}, {'o', 4}, {'u', 5}};
int letter_count[6] = {0};
long long ans = 0;
while (r2 < word.size()) {
for (; r1 < word.size() && ((vowel_count < 5 && mp[word[r1]]) || letter_count[0] < k); ++r1) {
int index = mp[word[r1]];
if (letter_count[index]++ == 0 && index) {
++vowel_count;
}
}
for (r2 = r1; r2 < word.size() && mp[word[r2]] > 0; ++r2);
for (; l < r2 && letter_count[0] == k; ++l) {
for (; r1 < r2 && (vowel_count < 5); ++r1) {
int index = mp[word[r1]];
if (letter_count[index]++ == 0 && index) {
++vowel_count;
}
}
if (vowel_count == 5) ans += (r2-r1)+1;
if (int index = mp[word[l]]; --letter_count[index] == 0 && index) {
--vowel_count;
}
}
if (!k && l == r2 && r2 < word.size()) {
++l;
++r1;
++r2;
}
}
return ans;
}
};
complexity
- Time:
O(n)- Space:
O(1)
learnings
forloops are a lot more versatile than you think; they do not just have to run untili < array.size()