- Choose the invariant that makes a window valid or useful.
- Advance the right boundary and add the new element.
- Move the left boundary only as needed while maintaining the invariant and updating the answer.
Code notes
- 53 lines of C++ from the credited upstream file 3306.cpp.
- The implementation visibly relies on hash lookup.
- 2 loop blocks detected.
Complexity
Confirm that neither pointer moves backwards; if so, the scan is usually linear apart from the window’s data-structure operations.
Check the problem constraints before deciding whether this complexity will pass.
Use this to learn the idea, then write your own version.
1class Solution {2 public:3 4 long long countOfSubstrings(string word, int k) {5 return substringsWithAtMost(word, k) - substringsWithAtMost(word, k - 1);6 }7 8 private:9 10 11 long substringsWithAtMost(const string& word, int k) {12 if (k == -1)13 return 0;14 15 long res = 0;16 int vowels = 0;17 int uniqueVowels = 0;18 unordered_map<char, int> vowelLastSeen;19 20 for (int l = 0, r = 0; r < word.length(); ++r) {21 if (isVowel(word[r])) {22 ++vowels;23 if (const auto it = vowelLastSeen.find(word[r]);24 it == vowelLastSeen.end() || it->second < l)25 ++uniqueVowels;26 vowelLastSeen[word[r]] = r;27 }28 while (r - l + 1 - vowels > k) {29 if (isVowel(word[l])) {30 --vowels;31 if (vowelLastSeen[word[l]] == l)32 --uniqueVowels;33 }34 ++l;35 }36 if (uniqueVowels == 5)37 38 39 40 res += min({vowelLastSeen['a'], vowelLastSeen['e'], vowelLastSeen['i'],41 vowelLastSeen['o'], vowelLastSeen['u']}) -42 l + 1;43 }44 45 return res;46 }47 48 bool isVowel(char c) {49 static constexpr string_view kVowels = "aeiou";50 return kVowels.find(c) != string_view::npos;51 }52};53