1 题目描述
输入一个字符串s,以及数字k,要求返回最长子串长度,字串要求其中的每个字符的频数超过k。
注意:字符串中的字符只包含所有小写字母
2 解题思路
2.1 分治
对字符串当中的每个小写字母计数
- 如果字符串所有的字母频数都超过k,当前串就是要求的最长子串
- 如果字符串中存在某个小写字母,但这个小写字母的个数小于k,那么说明当前字符串不是要求的最长字串,所有包含了这个小写字母的串都不可能满足条件,我们需要把这个小写字母剔除,将当前串分成若干个子串
- 对每个子串进行相同操作求解子串的最长子串长度
- 返回子串中最长子串长度的最大值
时间复杂度 O(n* m)
1、对当前字符串每个字母计数 O(n)
2、寻找应当被剔除的字母 O(26)
3、划分子字符串O(n)
4、递归层数最多为m,m代表字符类型个数,每层子串个数加起来不超过n
class Solution {
public int longestSubstring(String s, int k) {
int n = s.length();
return dfs(s,k,0,n - 1);
}
public int dfs(String s, int k,int left,int right){
int[] count = new int[26];
for(int i = left; i <= right; i ++){
count[s.charAt(i) - 'a'] += 1;
}
char split = 0;
for(int i = 0; i < 26 ; i++){
if(count[i] > 0 && count[i] < k){
split = (char)(i + 'a');
break;
}
}
if(split == 0){
return right - left + 1;
}
int max = 0;
int i = left;
int start = 0;
int end = 0;
while(i <= right){
while(i <= right && s.charAt(i) == split){
i ++;
}
if(i > right){
break;
}
start = i;
while( i <= right && s.charAt(i) != split){
i ++;
}
end = i - 1;
int maxForCurrent = dfs(s,k,start,end);
max = Math.max(maxForCurrent,max);
}
return max;
}
}