1. 题目
给你一个字符串 s
和一个整数 k
,请你找出 s
中的最长子串, 要求该子串中的每一字符出现次数都不少于 k
。返回这一子串的长度。
2. 示例
示例1:
输入:s = "aaabb", k = 3
输出:3
解释:最长子串为 "aaa" ,其中 'a' 重复了 3 次
示例2:
输入:s = "ababbc", k = 2
输出:5
解释:最长子串为 "ababb" ,其中 'a' 重复了 2 次, 'b' 重复了 3 次
3. 提示
-
1 <= s.length <= 104
-
s
仅由小写英文字母组成 -
1 <= k <= 105
4. 题解
我最开始看这题的时候,也跟在做的各位一样,毫无头绪;
看到连续子串,我的第一想法是滑动窗口,尝试过,不好做。
接着,发现里面暗含递归。
这道题的K很关键,我的第一想法都是想法将它作为递归条件。
就是某个字符在整个字符串里的个数小于k,此时将它划分为两半,左边用来递归,右边用来递归(分治+递归)。
但递归有始就有终。
开始的想法是,递归到最小子串时,此时只有两种可能就是:某个子串满足条件,此时不能再进行递归,子串的长度就是需要返回的值,还有一种,就不满足条件,此时子串的长度一定为0,也返回子串长度即可。
5. Code
1 public class LongestSubstring {
2 public int longestSubstring(String s, int k) {
3 Map<Character, Integer> map = new HashMap<>();
4 for(int i = 0; i < s.length(); i++) {
5 if(map.containsKey(s.charAt(i))) {
6 map.put(s.charAt(i), map.get(s.charAt(i)) + 1);
7 } else {
8 map.put(s.charAt(i), 1);
9 }
10 }
11 int left = 0, right = 0;
12 while(left <= right && right < s.length()) {
13 if(map.get(s.charAt(right)) >= k) {
14 right++;
15 } else {
16 return Math.max(longestSubstring(s.substring(left, right), k), longestSubstring(s.substring(right+1), k));
17 }
18 }
19 return s.length();
20 }
21
22 public static void main(String[] args) {
23 String s = "ababbc";
24 int k = 2;
25 System.out.println(new LongestSubstring().longestSubstring(s, k));
26 }
27 }