给你一个下标从 0 开始的字符串 s
,只包含小写英文字母和一个整数 count
。如果 s
的 子串 中的每种字母在子串中恰好出现 count
次,这个子串就被称为 等计数子串。
返回 s
中 等计数子串 的个数。
子串 是字符串中连续的非空字符序列。
示例 1:
输入: s = "aaabcbbcc", count = 3 输出: 3 解释: 从下标 0 开始到下标 2 结束的子串是 "aaa"。 字母 “a” 在子串中恰好出现了 3 次。 从下标 3 开始到下标 8 结束的子串是 "bcbbcc"。 字母 “b” 和 “c” 在子串中恰好出现了 3 次。 从下标 0 开始到下标 8 结束的子串是 "aaabcbbcc"。 字母 “a”、“b” 和 “c” 在子串中恰好出现了 3 次。
示例 2:
输入: s = "abcd", count = 2 输出: 0 解释: 每种字母在 s 中出现的次数小于 count。 因此,s 中没有子串是等计数子串,返回 0。
示例 3:
输入: s = "a", count = 5 输出: 0 解释: 每种字母在 s 中出现的次数小于 count。 因此,s 中没有子串是等计数子串,返回 0。
提示:
1 <= s.length <= 3 * 10^4
1 <= count <= 3 * 10^4
s
只由小写英文字母组成。
提示 1
The brute force solution is to check every substring, which would TLE. How can we improve this solution?
提示 2
In an equal count substring, the first character appears count times, the second character appears count times, and so on.
提示 3
The length of an equal count substring is the number of unique characters multiplied by count.
提示 4
The length of all equal count substrings are multiples of count.
解法:滑动窗口
class Solution {
public int equalCountSubstrings(String s, int count) {
int n = s.length();
if (n < count) {
return 0;
}
int ans = 0;
// 等计数子串的长度为count的整数倍,有多少不同的字母,其长度就是count的多少倍
// 最多有26种字母,所以长度最多为count的26倍
for (int i = 1; i * count <= n && i <= 26; i++) {
int len = i * count;
int left = 0;
int right = 0;
// 记录窗口内各种字母的数量
int[] window = new int[26];
// 记录窗口内 字母种类 的数量
int valid = 0;
while (right < n) {
if (window[s.charAt(right) - 'a'] == 0) {
valid++;
}
window[s.charAt(right) - 'a']++;
// 如果滑动窗口内的某个字母数量超过count,则此窗口已经不符合要求,左指针右移
while (window[s.charAt(right) - 'a'] > count) {
window[s.charAt(left) - 'a']--;
if (window[s.charAt(left) - 'a'] == 0) {
valid--;
}
left++;
}
// 窗口长度为i * count时,检查其字母种类数是否为i
if (right - left + 1 == len) {
if (valid == i) {
ans++;
}
window[s.charAt(left) - 'a']--;
if (window[s.charAt(left) - 'a'] == 0) {
valid--;
}
left++;
}
right++;
}
}
return ans;
}
}
复杂度分析
- 时间复杂度:O(n),n 是 字符串 的长度,最坏情况下,时间复杂度为O(26n) = O(n) 。
- 空间复杂度:O(1)。