【JZOJ100046】收集卡片【模擬】
阿新 • • 發佈:2018-12-15
題目大意:
題目連結: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\n",ans);
return 0;
}
題外話
也可以用字首和+二分做,時間複雜度 。