【题解】力扣395. 至少有 K 个重复字符的最长子串

395. 至少有 K 个重复字符的最长子串

题目来源

395. 至少有 K 个重复字符的最长子串

思路

方法一 分治+递归

  • 重点:我们在调用递归函数的时候,把递归函数当做普通函数(黑箱)来调用,即明白该函数的输入输出是什么,而不用管此函数内部在做什么。

借住这道题,来详细理解递归

  1. 递归最基本的是记住递归函数的含义(务必牢记函数定义):本题longestSubstring(s,k)函数表示的就是题意,即求一个最长的子字符串的长度,该子字符串中每个字符出现的次数都最少为\(k\)。函数入参\(s\)是表示源字符串;\(k\)是限制条件,即子字符串中每个字符出现最少的次数;函数返回结果是满足题意的最长子字符串长度。
  2. 递归的终止条件(能直接写出最简单的case):如果字符串\(s\)的长度少于\(k\),那么一定不存在满足题意的子字符串,返回\(0\)
  3. 调用递归(重点):如果一个字符\(c\)\(s\)中出现的次数少于\(k\)次,那么\(s\)中所有的包含\(c\)的子字符串都不能满足题意。所以,应该在\(s\)的所有不包含\(c\)的子字符串中继续寻找结果:把\(s\)按照\(c\)分割(分割后每个子串都不包含\(c\)),得到很多子字符串\(t\)下一步要求t作为源字符串的时候,它的最长的满足题意的子字符串长度(到现在为止,我们把大问题分割为了小问题\((s \to t)\))。此时我们发现恰好已经定义了函数longestSubstring(s,k)就是来解决这个问题的!所以直接把longestSubstring(s,k)函数拿来用,于是形成了递归。
  4. 未进入递归时的返回结果:如果\(s\)中的每个字符出现的次数都大于\(k\)次,那么\(s\)就是我们要求的字符串,直接放回该字符串的长度。

总之,通过分析,我们可以知道:我们不是为了递归而递归。而是因为我们把大问题拆解成了小问题,恰好有函数可以解决小问题,所以直接用这个函数。由于这个函数正好是本省,所以我们把此现象叫做递归。小问题是原因,递归时结果。而递归函数到底怎么一层层展开与终止的,不要用大脑去想,这是计算机干的事。我们只用把递归函数当做一个能解决问题的黑箱就够了,把更多的注意力放在拆解子问题、递归终止条件、递归函数的正确性上来。

代码

class Solution {
    public int longestSubstring(String s, int k) {
        int len = s.length();
        if(len < k) return 0;
        Map<Character, Integer> count = new HashMap<Character, Integer>();
        for(int i = 0;i<len;i++){
            count.put(s.charAt(i), count.getOrDefault(s.charAt(i), 0)+1);
        }
        for(char c : count.keySet()){
            if(count.get(c) < k){
	            int res = 0;
                for(String t : s.split(String.valueOf(c))){
                    res = Math.max(res, longestSubstring(t, k));
                }
            	return res;
            }
        }
        return len;
    }
}

参考来源

  1. 负雪明烛
posted @ 2021-03-15 10:51  zzzzzy2k  阅读(102)  评论(0编辑  收藏  举报