至少有k个字符串——递归的实践

一、题目

给你一个字符串 s 和一个整数 k ,请你找出 s 中的最长子串, 要求该子串中的每一字符出现次数都不少于 k 。返回这一子串的长度。

《至少有k个字符串——递归的实践》

二、解析

本题要求的一个最长的子字符串的长度,该子字符串中每个字符出现的次数都最少为 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 → t))。此时我们发现,恰好已经定义了函数 longestSubstring(s, k) 就是来解决这个问题的!所以直接把 longestSubstring(s, k) 函数拿来用,于是形成了递归。
  4. 未进入递归时的返回结果:如果 s 中的每个字符出现的次数都大于 k 次,那么 s 就是我们要求的字符串,直接返回该字符串的长度。

三、代码

class Solution3 {
public:
	//最长子串,每个字符至少要包含k次
	int longestSubstring(string s, int k) {

		int length = s.size();
		if (k < 2) return length;
		if (length < k) return 0;
		int m[26] = { 0 }; //记录每个字符出现的次数
		for (auto c : s) ++m[c - 'a'];
		int i = 0;
		while (i < length && m[s[i] - 'a'] >= k) ++i;
		if (i == length) return length;
		int left = longestSubstring(s.substr(0, i), k);
		while (i < length && m[s[i] - 'a'] < k) ++i;
		int right = longestSubstring(s.substr(i), k);
		return max(left, right);
	}

参考:

https://leetcode-cn.com/problems/longest-substring-with-at-least-k-repeating-characters/solution/jie-ben-ti-bang-zhu-da-jia-li-jie-di-gui-obla/

 

 

    原文作者:物随心转
    原文地址: https://blog.csdn.net/sinat_31608641/article/details/114240079
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞