问题:
难度:medium
说明:
给出一个字符串,一个数字 K,然后将字符串里面 字符任意顺序、长度最长 所有字符重复次数都 >= K 的 子串(连续子序列)返回。
题目连接:https://leetcode.com/problems/longest-substring-with-at-least-k-repeating-characters/
输入范围:
1 <= s.length <= 104
s
consists of only lowercase English letters.1 <= k <= 105
输入案例:
Example 1:
Input: s = "aaabb", k = 3
Output: 3
Explanation: The longest substring is "aaa", as 'a' is repeated 3 times.
Example 2:
Input: s = "ababbc", k = 2
Output: 5
Explanation: The longest substring is "ababb", as 'a' is repeated 2 times and 'b' is repeated 3 times.
我的代码:
思考了很久,这个也 类似于 分治法的一种处理,但是并没有更好,更方便的思路,只好按照比较系统性的写法处理,所以第一版特别长,优化之后应该会断点。
1、算一次整个串的词频
2、然后把词频低于 k 的字符词频置 0
3、因为进行了词频置 0 ,所以出现了 0 词频划分的区间,再对每个区间进行词频重算,继续 2 步骤
4、最后是统计每个区间长度即可
class Solution {
public int longestSubstring(String s, int k) {
if(k < 2) return s.length();
int len = s.length(), total = 0, temp = 0;
int[] fre = new int[len];
int[] totals = new int[26];
char[] chs = s.toCharArray();
for(char ch : chs) // 先算一次词频
totals[ch - 'a'] ++;
for(int i = 0;i < len;i ++) // 对整个串都赋值上词频
fre[i] = totals[chs[i] - 'a'];
boolean zeroF = false;
while(true) {
for(int i = 0;i < len;i ++)
if(fre[i] != 0 && fre[i] < k) { // 将低于 k 除 0 外的词频置为0
zeroF = true;
fre[i] = 0;
}
if(!zeroF) break;
for(int i = 0;i < len;i ++) { // 把每个 0 对应的区间都进行重复计算
if(fre[i] == 0) {
reclculate(i + 1, len, fre, chs);
} else if(i == 0) recalculate(0, len, fre, chs);
}
zeroF = false;
}
for(int i = 0;i < len;i ++) { // 最后获得最长的区间长度
if(fre[i] == 0) {
total = Math.max(temp, total);
temp = 0;
} else
temp ++;
}
return Math.max(temp, total);
}
// 重新计算每个区间的重复次数
private void recalculate(int i, int len, int[] fre, char[] chs) {
if(i < len && fre[i] != 0) {
int[] totals = new int[26];
for(int j = i;j < len;j ++) {
if(fre[j] == 0) {
len = j;
break;
}
totals[chs[j] - 'a'] ++;
}
for(int j = i;j < len;j ++) {
fre[j] = totals[chs[j] - 'a'];
}
}
}
}