前言
递归的思想还是比较容易理解的,代码写起来一如既往的那么艰难。
提示:以下是本篇文章正文内容,下面代码可供参考
一、题目の描述
找到给定字符串(由小写字符组成)中的最长子串 T , 要求 T 中的每一字符出现次数都不少于 k 。输出 T 的长度。
示例 1:
输入:
s = “aaabb”, k = 3
输出:
3
最长子串为 “aaa” ,其中 ‘a’ 重复了 3 次。
示例 2:
输入:
s = “ababbc”, k = 2
输出:
5
最长子串为 “ababb” ,其中 ‘a’ 重复了 2 次, ‘b’ 重复了 3 次。
二、使用步骤
递归+分治
- 对于字符串 s,如果存在某个字符ch,它的出现次数大于 0 且小于 k,则任何包含ch 的子串都不可能满足要求;
- .将字符串按照ch 切分成若干部分,则满足要求的最长子串一定出现在某个被切分的部分,而不能跨越一个或多个段;
- 考虑分治的方式求解本题。
代码如下(示例):
int dfs(char* s, int l, int r, int k) {
int cnt[26];
memset(cnt, 0, sizeof(cnt));
for (int i = l; i <= r; i++) {
cnt[s[i] - 'a']++;//由小写字母转换为数字进行表示
}
char split = 0;
for (int i = 0; i < 26; i++) {
if (cnt[i] > 0 && cnt[i] < k) {
split = i + 'a';//标记不满足条件的字符
break;
}
}
if (split == 0) {
return r - l + 1;//出现的字符均满足条件,返回数组长度
}
int i = l;//i代表当前字符串首位
int ret = 0;
while (i <= r) {
while (i <= r && s[i] == split) {
i++;//根据不满足条件的字符进行分割
}
if (i > r) {
break;
}
int start = i;//start作为新的首位
while (i <= r && s[i] != split) {
i++;//寻找字符串末位
}
int length = dfs(s, start, i - 1, k);
ret = fmax(ret, length);
}
return ret;
}
int longestSubstring(char* s, int k) {
return dfs(s, 0, strlen(s) - 1, k);
}
三、总结
递归和分治的解法其实相对来说容易理解,只是我的代码功底实在是太差了,又是一点一点研究官方代码的一天,冲冲冲!