题意:在字符串中找一个最短的包含其所有字母种类的子串,输出最小长度
题解:先找到原串中所有的字母种类,然后做尺取法。R往右移,直到包含所有种类。再L右移,同时减去L字符的个数。更新最小长度。
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 100100
char str[maxn];
int big[30];//分别记录某种大写字母出现的个数
int lit[30];//分别记录某种小写字母出现的个数
int main()
{
int n,i,a,j;
while(scanf("%d",&n)!=EOF)
{
memset(big,0,sizeof(big));
memset(lit,0,sizeof(lit));
scanf("%s",str);
int sum=0;
for(i=0;i<n;++i)
{
if('a'<=str[i]&&str[i]<='z')//统计字符串中一共有多少种字符
{
a=str[i]-'a';
if(!lit[a])
{
sum++;
lit[a]=1;
}
}
else
{
a=str[i]-'A';
if(!big[a])
{
sum++;
big[a]=1;
}
}
}
int cnt=0;
int start=0,ans=n;
memset(big,0,sizeof(big));
memset(lit,0,sizeof(lit));
for(i=0;i<n;++i)
{
if('a'<=str[i]&&str[i]<='z')
{
a=str[i]-'a';
if(!lit[a])
cnt++;
lit[a]++;
}
if('A'<=str[i]&&str[i]<='Z')
{
a=str[i]-'A';
if(!big[a])
cnt++;
big[a]++;
}
if(cnt==sum)//子串包含所有字符种类时,子串首部往后移动,并记录最短的满足条件的子串长度
{
while(cnt==sum)
{
if(i-start+1<ans)
ans=i-start+1;
if('a'<=str[start]&&str[start]<='z')
{
a=str[start]-'a';
lit[a]--;
if(!lit[a])
cnt--;
}
if('A'<=str[start]&&str[start]<='Z')
{
a=str[start]-'A';
big[a]--;
if(!big[a])
cnt--;
}
start++;
}
}
}
printf("%d\n",ans);
}
return 0;
}