2020牛客寒假算法基础集训营1 题目G:eli和字符串(前缀和)

题目描述:

eli 拿到了一个仅由小写字母组成的字符串。
她想截取一段连续子串,这个子串包含至少 K 个相同的 某个字母
她想知道,子串的长度最小值是多少?
注:所谓连续子串,指字符串删除头部和尾部的部分字符(也可以不删除)剩下的字符串。例如:对于字符串“arcaea”而言,“arc”、“rcae”都是其子串。而“car”、“aa”则不是它的子串。

输入描述:

第一行输入两个正整数 nk (1<= k <= n <= 200000)
输入仅有一行,为一个长度为 n 的、仅由小写字母组成的字符串。

输出描述:

如果无论怎么取都无法满足条件,输出 -1
否则输出一个正整数,为满足条件的子串长度最小值。

分析:

通过定义两个指针,分别为l和r,开始的时候都指向字符串的开始位置。因为我们要找到k个相同的某个字符,所以,还需要对每一个字母遍历,对于每一个遍历的字母,使用l记录下字母开始的位置,使用r记录下下此字母出现k次时候的位置,记录下这个长度,之后,移动l指针,至其到达此字母第二次出现的位置,同样,移动r指针,至其到达此字母第k+1次的位置,之后,同样进行此操作,最后当r到达字符串的长度时停止,取其中长度最小的,最后遍历每一个字母,再取字母中长度最小的。

代码如下:

#include <iostream>
#include <cstring>
#include <cstdio>
#define INF 0x3f3f3f3f
using namespace std;

int dp[200005][30];
int n,k;
int ans = INF;
string str;

int main()
{
	scanf("%d%d",&n,&k);
	cin >> str;
	dp[0][str[0]-'a'] = 1;
	for(int i=1;i<n;++i)
	{
		for(int j=0;j<26;++j)
			dp[i][j] = dp[i-1][j];
		dp[i][str[i]-'a']++;
	}
	for(int i=0;i<26;++i)
	{
		int l=0,r=0;
		if(dp[n-1][i] < k) continue;
		while(l<n&&dp[l][i]==0) l++;
		while(r<n&&dp[r][i]<k) r++;
		ans = min(ans,r-l+1);
		l++;
		while(l<n)
		{
			while(str[l]-'a' != i && l<n) l++;
			r++;
			while(str[r]-'a' != i && r<n) r++;
			if(r==n) break;
			ans = min(ans,r-l+1);
			++l;
		}
	}
	if(ans == INF) printf("-1\n");
	else
		printf("%d\n",ans);
	return 0;
}
发布了33 篇原创文章 · 获赞 2 · 访问量 1710

猜你喜欢

转载自blog.csdn.net/weixin_42469716/article/details/104206327
今日推荐