题解
本题使用分治策略,如果某个字符的出现次数小于k,则用它将数组分开,再把每个子数组组委参数递归执行.如果都大于k,则将该字符串的长度返回.
用一个字符分割,往深了分割各子字符串,这个字符分割完成,使用另一个字符进行分割,而不是一次用多个字符进行分割.这个题递归有些绕
代码
//301-295- 至少有 K 个重复字符的最长子串-0105
int longestSubstringRes=0;
public int longestSubstring(String s, int k) {
if (s.length()<k){
return 0;
}
// 统计个数
HashMap<Character, Integer> map = new HashMap<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
map.put(c,map.getOrDefault(c,0)+1);
}
// 分割
for (Map.Entry<Character, Integer> entry : map.entrySet()) {
if (entry.getValue()<k){
for (String s1 : s.split(entry.getKey().toString())) {
// 对分割完成的子串进行递归
longestSubstringRes=Math.max(longestSubstringRes,longestSubstring(s1,k));
}
return longestSubstringRes;
}
}
return s.length();
}
法二 滑动窗口法
https://leetcode.cn/problems/longest-substring-with-at-least-k-repeating-characters/solution/xiang-jie-mei-ju-shuang-zhi-zhen-jie-fa-50ri1/
当窗口内满足条件的种类=窗口内字符的种类, 得到一个结果
窗口内的字符种类一定的情况下,求满足条件的子串
未到达p类–>判断–>达到p类–>判断–>p+1类–>left右移达到p类–>
当为p+1类时执行同样的步骤
滑动窗口逻辑上优点难度,看代码与注释
// 滑动窗口
public int longestSubstring(String s, int k) {
int cnt[]=new int[26]; // 统计各字符个数
int res=0;
for (int p = 1; p <=26 ; p++) { // p代表窗口内字符的种类
Arrays.fill(cnt, 0);
int left=0,right=0,totalKind=0,matchKind=0;// totalKind 总种类 matchKind: 符合条件的种类
while (right<s.length()){
char c = s.charAt(right);
int index=c-'a';
cnt[index]++;
if (cnt[index]==1){// 新加入一类
totalKind++;
}
if (cnt[index]==k){//如果满足条件
matchKind++;
}
// 如果总种类大于p,左指针右移,减小种类
while (totalKind>p){
char c1 = s.charAt(left++);// 右移
int index1 = c1 - 'a';
cnt[index1]--;
if (cnt[index1]==0){// 去除该元素后少了一类
totalKind--;
}
if (cnt[index1]==k-1){// 满足条件的少了一类
matchKind--;
}
}
// 判断 当为p类时进行判断
if (totalKind==matchKind){
res=Math.max(res,right-left+1);
}
right++;
}
}
return res;
}