找到给定字符串(由小写字符组成)中的最长子串 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
的字母。但此时,由于左边窗口内的字母,有一部分出现次数在窗口右侧,因此此时左边窗口内的子串也不一定就符合需求,因此还有继续往下递归。
以字符串"aacbbbdc"
,k=2
为例,第一轮将字符串分割为aacbbb
和c
两部分,中间的字符d
出现次数小于2
不考虑。随后递归查找aacbbb
中的最长子串,进一步分割为aa
和bbb
最终返回最长子串长度为3
,而第一层递归右侧返回结果是1
,因此最终结果为3
.
class Solution {
public:
int longestSubstring(string s, int k) {
if(s.empty() || s.size() < 1)
return 0;
if(k <= 1)
return s.size();
unordered_map<char, int> map;
for(char c : s){
map[c]++;
}
int i = 0;
while(i < s.size() && map[s[i]] >= k){
i++;
}
if(i == s.size())
return i;
int left = longestSubstring(s.substr(0, i), k);
while(i < s.size() && map[s[i]] < k){
i++;
}
int right = longestSubstring(s.substr(i), k);
return max(left, right);
}
};