1. 至少有K个字母的最长子串
题目描述:给你一个字符串 s
和一个整数 k
,请你找出 s
中的最长子串, 要求该子串中的每一字符出现次数都不少于 k
。返回这一子串的长度。
算法思路:题目要求子串中每个字母的个数都要大于k,可以先统计字符串中每个字母出现的频率,如果存在某个字母a在整个字符串中出现的频率小于k,但是满足条件的子串绝对不可能包含字母a,因此可以用字母a将字符串分割成几个子串,对子串继续上述的判断方式,直到不存在这样的字母或者字符串长度为0。自此,我们将一个大问题分割成了几个小问题,可以使用递归的方式解决。递归的返回就是满足条件的子串长度,递归结束条件:字符串长度为0或者字符串中所有字母的出现频率都大于等于k。
public int longestSubstring(String s, int k) { return longestSubstring(s, k, 0, s.length() - 1); } public int longestSubstring(String s, int k, int start, int end) { if (end - start + 1 < k) { return 0; } int[] total = new int[26]; // 统计字符串中每个字母个数, 找出小于k个的字母 for (int i = start; i <= end; i++) { total[s.charAt(i) - 'a']++; } int longestLen = 0; int left = start; for (int i = start; i <= end; i++) { // 字母在字符串中出现频率小于k, 需要切割子串, 继续递归判断 if (total[s.charAt(i) - 'a'] < k) { longestLen = Math.max(longestLen, longestSubstring(s, k, left, i - 1)); left = i + 1; } } // 字符串被切割过, 需要处理切割后的最后一段 if(left != start) { return Math.max(longestLen, longestSubstring(s, k, left, end)); } // 字符串没有被切割过, 满足至少k个重复字符条件 return end - start + 1; }