Find the length of the longest substring T of a given string (consists of lowercase letters only) such that every character in T appears no less than k times.
Example 1:
Input:
s = "aaabb", k = 3
Output:
3
The longest substring is "aaa", as 'a' is repeated 3 times.
Example 2:
Input:
s = "ababbc", k = 2
Output:
5
The longest substring is "ababb", as 'a' is repeated 2 times and 'b' is repeated 3 times.
思路1:这用双指针来做;因为unique char可以有1,2,3,。。。26个可能性,那么可以把问题分解为26个不同维度的小问题,求uniqueChar 是m个,同时出现次数不小于k的最长substring 长度,那么26 * N就可以完成。核心思想就是; uniqueNum是个给定的数1,2,3,4,5...26, 我要求的是countNum == uniqueNum,同时我也记录一下nolessthank的数目,如果同样等于 unqiueNum,证明我找到一个candidate; 然后求这26个unique char的最大值,O(26*n) = O(n);
class Solution {
public int longestSubstring(String s, int k) {
if(s == null || s.length() == 0) {
return 0;
}
int maxlen = 0;
for(int i = 1; i <= 26; i++) {
maxlen = Math.max(maxlen, getLength(s, k, i));
}
return maxlen;
}
// countNum move到 uniqueNum的时候,判断一下nolessthank是不是也是unqiueNum;
private int getLength(String s, int k, int uniqueNum) {
int countNum = 0;
int j = 0;
char[] ss = s.toCharArray();
int[] scount = new int[256];
int nolessthank = 0;
int maxlen = 0;
for(int i = 0; i < ss.length; i++) {
// move j;
while(j < ss.length && countNum <= uniqueNum) {
if(scount[ss[j]] == 0) {
if(countNum == uniqueNum) {
break;
}
countNum++;
}
scount[ss[j]]++;
if(scount[ss[j]] == k) {
nolessthank++;
}
j++;
}
// update res;
if(countNum == uniqueNum && nolessthank == uniqueNum) {
maxlen = Math.max(maxlen, j - i);
}
// move i;
if(scount[ss[i]] == k) { // 频率只能从k开始算;只要小于k,那么就是nolessthank--;
nolessthank--;
}
scount[ss[i]]--;
if(scount[ss[i]] == 0) {
countNum--;
}
}
return maxlen;
}
}
思路2:Divide and conquer; 基本原理是,先遍历整个string,并记录每个不同的character的出现次数。如果所有character出现次数都不小于k,那么说明整个string就是满足条件的longest substring,返回原string的长度即可;如果有character的出现次数小于k,假设这个character是c,因为满足条件的substring永远不会包含c,所以满足条件的substring一定是在以c为分割参考下的某个substring中。所以我们需要做的就是把c当做是split的参考,不要c,劈成两半,然后分别递归求解左边和右边,两者取最大。O(N^2);
class Solution {
public int longestSubstring(String s, int k) {
if(s == null || s.length() == 0) {
return 0;
}
int[] scount = new int[256];
char[] ss = s.toCharArray();
for(int i = 0; i < s.length(); i++) {
scount[ss[i]]++;
}
int index = 0;
while(index < s.length() && scount[ss[index]] >= k) {
index++;
}
if(index == s.length()) {
return s.length();
}
int left = longestSubstring(s.substring(0, index), k);
int right = longestSubstring(s.substring(index + 1), k); // 注意这里不需要c了,所以index + 1;
return Math.max(left, right);
}
}