今天做的最难的一道题(菜),一开始想要滑动窗口,不过估计做不出。所以用了递归分治,每次判断该字符串的字符是否都大于k次,就要每次都开一个哈希表,用数组记录就行。
用一个i遍历字符串,用while,记得判断越界操作,直到找到第一个小于k的或者越界就退出。如果是因为越界退出的,证明s中没有小于k的,返回整个s。
如果不是,证明s[i]这个字符出现次数小于k,我们计算它左边的复合要求的子串长度,用s.substr(0,i)即可。此时因为s[i]是不符合要求的,而s[i]又是重复出现的,我们用while跳过这些小于k次,退出循环时s[i]是复合要求的,也就是求右边的符合子串的长度,用s.substr(i)即可,会自动复制到最后一位,然后返回max(l,r)即可
class Solution {
public:
int longestSubstring(string s, int k) {
//滑动窗口中的每一个字符的出现次数都不小于k
//要求的是符合要求的最长子串,不是最短,所以left不用收缩
//可以考虑分治,找出哪个字母的出现次数小于k,就去它的左右找
if(k <= 1) return s.length();
if(s.length() < k) return 0;
int hash[26] = {0};
for(char c : s){
hash[c-'a']++;
}
//然后找到s中第一个出现次数小于k的,去它的左右两边找
int i = 0;
while(i < s.length() && hash[s[i]-'a'] >= k) i++;
//此时i可能走到头,也可能碰到了出现次数小于k的字符
if(i == s.length()) return s.length();
//substr有两个重载,一个参数的是从这个参数复制到尾,两个参数的是从第一个参数,复制第二个参数个数的字符
int l = longestSubstring(s.substr(0,i),k);
//此时要跳过中间这一个,因为i这个字符出现的次数小于k
//但是这个字符出现了可能不止1次,用while来跳过它
while(i<s.length() && hash[s[i]-'a'] < k) i++;
int r = longestSubstring(s.substr(i),k);
return max(l,r);
}
};