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