题目描述:
eli 拿到了一个仅由小写字母组成的字符串。
她想截取一段连续子串,这个子串包含至少 K 个相同的 某个字母 。
她想知道,子串的长度最小值是多少?
注:所谓连续子串,指字符串删除头部和尾部的部分字符(也可以不删除)剩下的字符串。例如:对于字符串“arcaea”而言,“arc”、“rcae”都是其子串。而“car”、“aa”则不是它的子串。
输入描述:
第一行输入两个正整数 n 和 k (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;
}