给你一个字符串 s 和一个整数 k ,请你找出 s 中的最长子串, 要求该子串中的每一字符出现次数都不少于 k 。返回这一子串的长度。
示例 1:
输入:s = “aaabb”, k = 3
输出:3
解释:最长子串为 “aaa” ,其中 ‘a’ 重复了 3 次。
示例 2:
输入:s = “ababbc”, k = 2
输出:5
解释:最长子串为 “ababb” ,其中 ‘a’ 重复了 2 次, ‘b’ 重复了 3 次。
提示:
- 1 <= s.length <= 104
- s 仅由小写英文字母组成
- 1 <= k <= 105
解析
通过昨天的无重复字符的最长子串,了解到滑动窗口算法,奈何本人还是太菜,还是看了别人的思路。
首先通过一个record的数组记录窗口的字符的种类的数量和各个字符的数量。然后通过26次循环(每一次循环只允许i个不同字符的出现),如果最后到达制定数量的字符的个数等于当次循环限定的个数,则与以前的结果进行比较,更新结果。
实现代码
class Solution {
public:
int longestSubstring(string s, int k) {
int res = 0, record[26]; //记录出现不同字符的个数
for(int i = 1 ; i <= 26 ; i++){ //每次循环只能有i种字符
memset(record , 0 , sizeof(record));
int left = 0 , right = 0;
int difcount = 0,count = 0; //记录不同的字符数,个数大于等于k的字符数
while(right < s.size()){
//向右扩大窗口
int add_index = s[right] - 'a'; //记录字符的个数
record[add_index] += 1;
if(record[add_index] == 1) //首次出现,不同字符的数量加一
difcount += 1;
if(record[add_index] == k)
count ++;
right++;
while(difcount > i && left < right){
//向左缩减窗口,直到只有i种字符
int del_count = s[left] - 'a';
if(record[del_count] == k)
count --;
if(record[del_count] == 1)
difcount --;
record[del_count]--;
left ++;
}
//如果不同的字符的个数 == 本次循环限制不同字符的个数 == 个数大于等于k的字符数
if(difcount == i && difcount == count)
res = max(res , right - left);
}
}
return res;
}
};