题目链接
1. 题目要求
- 字符串每个元音字母至少出现一次
- 恰好包含k个辅音字母
2. 解决方案
- 考虑滑动窗口
- 窗口内始终保证
- 每个字母记录左测离自己最近的辅音字母的索引 ( 不包括当前字母 )
- 当窗口满足以上条件时, 如何累加ans?
- 设窗口最左测的字母索引为
left
ans += left - nearestConsonant[left]
- 考虑窗口的各种情况
- 窗口刚好满足情况 — 累加
ans
- 缺少元音字母 — 右移
- 可以减少元音字母 — 左移
- 辅音字母小于k — 右移
- 辅音字母大于k — 左移
3. 代码实现
public static long countOfSubstrings(String word, int k) {
int N = word.length();
boolean[] meta = new boolean[32];
meta['a' - 'a'] = true;
meta['e' - 'a'] = true;
meta['i' - 'a'] = true;
meta['o' - 'a'] = true;
meta['u' - 'a'] = true;
int[] nearestConsonant = new int[N];
int nearest = -1;
for (int i = 0; i < N; i++) {
nearestConsonant[i] = nearest;
if (!meta[word.charAt(i) - 'a'])
nearest = i;
}
int left = 0;
int right = 0;
int[] window = new int[32];
long ans = 0;
while (right < N) {
int index = word.charAt(right) - 'a';
window[index]++;
int m;
while (direction(window, meta, k, left, word) < 0) {
int leftIndex = word.charAt(left) - 'a';
window[leftIndex]--;
left++;
}
if (direction(window, meta, k, left, word) == 0) {
ans += left - nearestConsonant[left];
}
right++;
}
return ans;
}
public static int direction(
int[] window,
boolean[] meta,
int k,
int left,
String word
) {
int ac = window['a' - 'a'];
int ec = window['e' - 'a'];
int ic = window['i' - 'a'];
int oc = window['o' - 'a'];
int uc = window['u' - 'a'];
int sum = 0;
for (int w : window)
sum += w;
if (ac == 0 || ec == 0 || ic == 0 || oc == 0 || uc == 0)
return 1;
int consonant = sum - ac - ec - ic - oc - uc;
if (consonant < k)
return 1;
if (consonant > k)
return -1;
char leftestChar = word.charAt(left);
if (leftestChar == 'a' && ac > 1) return -1;
if (leftestChar == 'e' && ec > 1) return -1;
if (leftestChar == 'i' && ic > 1) return -1;
if (leftestChar == 'o' && oc > 1) return -1;
if (leftestChar == 'u' && uc > 1) return -1;
return 0;
}