题目
找到给定字符串(由小写字符组成)中的最长子串 T ,?要求?T?中的每一字符出现次数都不少于 k 。输出 T?的长度。
示例 1:
输入:
s = “aaabb”, k = 3
输出:
3
最长子串为 “aaa” ,其中 ‘a’ 重复了 3 次。
示例 2:
输入:
s = "ababbc", k = 2
输出:
5
最长子串为 "ababb" ,其中 'a' 重复了 2 次, 'b' 重复了 3 次。
分析
首先是统计每个字母出现的次数,然后根据要求k来调整滑窗的边界。滑窗边界初次调整结束后,需要再次调整
因为内部可能存在重复次数小于k的字母,如果找到,以这个字母为中心,划分成两个滑窗,然后进行递归并每
个滑窗二者中值最大的一个。
技术点附注:
1.首先是统计每个字母出现的次数,这个可以用unoredered_map。
2.其次由于需要统计最长子串长度,所以还需要一个滑窗,这个滑窗由于需要计算长度,所以需要设置一个
right和left。不像之前最长无重复子串问题,只需要确认一边即可。
3.如果初次调整后,字符串中间若出现不符合要求的情况,我们需要分隔两段继续找,这种情况优先考虑递归。
并且选择二者中最大的一个,需要记得用max函数
#include<unordered_map>
#include<string>
#include<algorithm>
using namespace std;
class MyClass
{
public:
int longestSubstring(string s, int k) {
int left = 0, right = s.size() - 1;
return slideWindows(s, k, left, right);
}
int slideWindows(string s, int k, int left, int right){
if (left > right){
return 0;
}
unordered_map<char, int> cnt;
for (int i = left; i <= right; ++i){
if (cnt[s[i]] < 0){
cnt[s[i]] = 1;
}
else{
++cnt[s[i]];
}
}
while (left <= right&&cnt[s[left]] < k)
{
cnt[s[left]]--;
++left;
}
while (left <= right&&cnt[s[right]] < k)
{
cnt[s[right]]--;
--right;
}
for (int i = left + 1; i < right; ++i)
{
if (cnt[s[i]] < k){
return max(slideWindows(s, k, left, i - 1), slideWindows(s, k, i + 1, right));
}
}
return right - left + 1;
}
};