- 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 Java from the credited upstream file 3306.java.
- The implementation visibly relies on hash lookup, ordered 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 3 public long countOfSubstrings(String word, int k) {4 return substringsWithAtMost(word, k) - substringsWithAtMost(word, k - 1);5 }6 7 8 9 private long substringsWithAtMost(String word, int k) {10 if (k == -1)11 return 0;12 13 long res = 0;14 int vowels = 0;15 int uniqueVowels = 0;16 Map<Character, Integer> vowelLastSeen = new HashMap<>();17 18 for (int l = 0, r = 0; r < word.length(); ++r) {19 if (isVowel(word.charAt(r))) {20 ++vowels;21 if (!vowelLastSeen.containsKey(word.charAt(r)) || vowelLastSeen.get(word.charAt(r)) < l)22 ++uniqueVowels;23 vowelLastSeen.put(word.charAt(r), r);24 }25 while (r - l + 1 - vowels > k) {26 if (isVowel(word.charAt(l))) {27 --vowels;28 if (vowelLastSeen.get(word.charAt(l)) == l)29 --uniqueVowels;30 }31 ++l;32 }33 if (uniqueVowels == 5) {34 35 36 37 final int minVowelLastSeen = Arrays.asList('a', 'e', 'i', 'o', 'u')38 .stream()39 .mapToInt(vowel -> vowelLastSeen.get(vowel))40 .min()41 .getAsInt();42 res += minVowelLastSeen - l + 1;43 }44 }45 46 return res;47 }48 49 private boolean isVowel(char c) {50 return "aeiou".indexOf(c) != -1;51 }52}53