题解 CF1354B 【Ternary String】
题意
给出一个字符串,只包含 \({1,2}\) 或 \({3}\) 。从中找出一个长度最短的子串,要求至少包含 \({1,2,3}\) 各一次,并输出其长度。
输入格式
本题有多组测试数据
第一行一个整数 \(t\) ,表示数据组数
接下来 \({t}\) 行,每行一个字符串 \(s\) ,它的每个字符只可能是 \(1,2\) 或 \(3\) 。\({s}\) 的长度不超过\(200000\)。
输出格式
对于每组数据,输出一行一个整数,表示最短的符合要求的子串的长度。如果不存在,输出 \(0\) 。
说明与提示
\(1 \le t \le20000\),
\(1 \le |s| \le 200000\)
Solution
我们可以开一个数组 $a $ ,其中 \(a_i\) 表示 i 上次出现的位置($ 1\le i \le 3$ ),初始时,\(a_i=-1\)。
然后线性扫过去,不断更新 \(a\),当停留在第 $ k $位时, a[ s[k]-'0' ]= k 。 显然,以第 \(k\) 位结尾的符合要求的子串长度为 k-min(a[1],a[2],a[3])+1 。此时我们可以更新 \(ans\) 。
代码 ↓
注意多测
#include<bits/stdc++.h>
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
const int MAXN=200010;
int t,a[5],ans=MAXN;
int main (){
scanf("%d",&t);
while(t--){
string s;
cin>>s;
a[1]=-1;a[2]=-1;a[3]=-1;ans=MAXN;
int ls=s.length();
for(int i=0;i<ls;i++){
a[s[i]-'0']=i;
int minn=MAXN;
for(int j=1;j<=3;j++){
minn=min(minn,a[j]);
}
if(minn==-1)continue;
ans=min(ans,i-minn+1);
if(ans==3)break;
}
if(ans==MAXN)printf("0\n");
else printf("%d\n",ans);
}
return 0;
}
本蒟蒻第一次写题解,巨佬轻喷
本博客作者:Werner_Yin(https://www.cnblogs.com/werner-yin/) ,转载时请注明出处,谢谢支持!