力扣题目
解题思路
java代码
力扣题目:
给你一个字符串 s
和一个整数 k
,请你找出 s
中的最长子串, 要求该子串中的每一字符出现次数都不少于 k
。返回这一子串的长度。
如果不存在这样的子字符串,则返回 0。
示例 1:
输入:s = "aaabb", k = 3 输出:3 解释:最长子串为 "aaa" ,其中 'a' 重复了 3 次。
示例 2:
输入:s = "ababbc", k = 2 输出:5 解释:最长子串为 "ababb" ,其中 'a' 重复了 2 次, 'b' 重复了 3 次。
提示:
1 <= s.length <= 104
s
仅由小写英文字母组成1 <= k <= 105
解题思路:
算法原理:
这道题使用分治法来找出给定字符串中满足每个字符出现次数至少为 k
的最长子串。
思路:
- 首先,统计给定区间内每个字符的出现次数。
- 找到一个出现次数小于
k
的字符作为分割点。 - 如果没有这样的分割点,说明当前区间满足条件,返回区间长度。
- 否则,根据分割点将区间分割为多个子区间,对每个子区间递归调用分治法函数,并更新最长子串长度。
代码分析:
- 在
dfs
函数中,首先创建字符计数数组cnt
统计字符出现次数。 - 然后找到分割字符
split
。 - 如果没有分割字符,直接返回区间长度。
- 否则,通过两个指针
i
来分割区间,并对每个子区间递归调用dfs
函数,更新最长子串长度。
时间复杂度:
平均情况下为 O(nlogn),最坏情况下为O(n²) 。其中 n
是字符串的长度。
空间复杂度:
平均情况下为O(logn) 用于递归栈,最坏情况下为 O(n) 。此外,创建字符计数数组使用了常数级的额外空间。
java代码:
package com.example.lib;
import java.util.Arrays;
public class Leetcode395 {
public static void main(String[] args) {
Leetcode395 leetcode395 = new Leetcode395();
System.out.println(leetcode395.longestSubstring("bbaa", 2));
System.out.println(leetcode395.longestSubstring("ababbc", 2));
}
public int longestSubstring(String s, int k) {
int n = s.length();
return dfs(s, 0, n - 1, k);
}
public int dfs(String s, int l, int r, int k) {
int[] cnt = new int[26];
for (int i = l; i <= r; i++) {
cnt[s.charAt(i) - 'a']++;
}
char split = 0;
for (int i = 0; i < 26; i++) {
if (cnt[i] > 0 && cnt[i] < k) {
split = (char) (i + 'a');
break;
}
}
if (split == 0) {
return r - l + 1;
}
int i = l;
int ret = 0;
while (i <= r) {
while (i <= r && s.charAt(i) == split) {
i++;
}
if (i > r) {
break;
}
int start = i;
while (i <= r && s.charAt(i) != split) {
i++;
}
int length = dfs(s, start, i - 1, k);
ret = Math.max(ret, length);
}
return ret;
}
}
更多详细内容同步到公众号,感谢大家的支持!
每天都会给刷算法的小伙伴推送明日一题,并且没有任何收费项