题目大意:
题目链接:https://jzoj.net/senior/#main/show/100046
题目图片:
http://wx3.sinaimg.cn/mw690/0060lm7Tly1fy7ghcpx5gj30j50fc0t4.jpg
http://wx4.sinaimg.cn/mw690/0060lm7Tly1fy7ghcpmnaj30j605dt8m.jpg
给出一个长的字符串,求最短连续子串包含了原串中含有的所有字母。
思路:
很明显的双指针模拟。
每次往前移指针,那么自然的可能需要后移指针。
用表示字母在中出现的次数。表示两个指针之间不同字母的个数。
当总字母数时,那么就是一个符合要求的子串,长度。
否则后移指针。
实际上为了简便,可以把字母转换成数字,分别表示,分别表示。
代码:
#include <cstdio>
#include <iostream>
using namespace std;
const int N=500010;
int n,ans,sum,num[100],a[N],maxn;
char c;
bool vis[100],ok;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
c=getchar();
while ((c<'a'||c>'z')&&(c<'A'||c>'Z')) c=getchar();
if (c>='a'&&c<='z') a[i]=c-'a'+1;
else a[i]=c-'A'+27; //转换成数字
if (!vis[a[i]])
{
maxn++;
vis[a[i]]=1;
}
}
int i=0,j=0;
ans=2147483647;
num[0]=23333;
while (j<=n)
{
num[a[i]]--;
if (!num[a[i]]) sum--; //该数子不在区间[i,j)内了
i++;
while (sum<maxn&&j<=n) //没有包含所有字母
{
j++;
if (j>n)
{
ok=1;
break;
}
if (!num[a[j]]) sum++; //新字母
num[a[j]]++;
}
if (ok) break;
ans=min(ans,j-i+1);
}
printf("%d
",ans);
return 0;
}
题外话
也可以用前缀和+二分做,时间复杂度。