C1000 完美子串题解

Description

yyc 非常喜欢完美的字符串,当然,一个完美的字符串一定是简约并且多样的。现在 yyc 有一个字符串,他想知道这个字符串的完美子串的最小长度是多少。
一个完美子串,是原串的一个连续子序列,并且包含了不同的 26 个大写字
母。
当然了如果 yyc 的字符串中并不存在完美子串,则输出 QwQ


设字符串长度为 n

40pts

先考虑最暴力的暴力,枚举一个长度 L,然后从左往右做一个“滑动窗口”,动态维护一个 26 大小的桶即可。如果一旦发现合法位置,输出当前的 L 并退出程序即可。时间复杂度 O(n2)

100pts

转换一下暴力,改为枚举一个右端点 r,然后从 r 开始往左扫,一旦发现已经扫过的区域内包含了所有字母,就把 rl+1min 然后 continue。最后输出 min 即可。
显然这样做没有优化时间复杂度,非常容易被卡到 n2。但我们发现,假设当前的右端点为 r,那我们在右端点为 r1 时已经扫出了一段合法的区间,这段区间完全可以现在继续使用,而不是扔掉不管。
想象现在我们有一段包含 26 个英文字母的合法区间,往右“添加”一个字母,肯定不会让这个区间变得不合法。于是我们就成功地把 r1 时找到的区间转移给了 r。但这样有可能不是最优。也许在向右“添加”后,左侧可以“吐出”一个字母,且保证区间合法。
所以用双指针做即可。每次让右端点 +1,然后维护左端点,取 min 即可。注意边界情况。

#include <bits/stdc++.h>
#include <bits/extc++.h>
#define INF 0x7fffffff
#define MAXN 2000005
#define eps 1e-9
#define foru(a,b,c)	for(int a=b;a<=c;a++)
#define RT return 0;
#define db(x)	cout<<endl<<x<<endl;
#define LL long long
#define int LL
#define LXF int
#define RIN rin()
#define HH printf("\n")
using namespace std;
inline LXF rin(){
	LXF x=0,w=1;
	char ch=0;
	while(ch<'0'||ch>'9'){ 
	if(ch=='-') w=-1;
	ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
	x=x*10+(ch-'0');
	ch=getchar();
	}
	return x*w;
}
string s;
int v[500],tot;
signed main(){
	cin>>s;
	int n=s.size();
	int l=0,r=0;
	v[s[0]]++;
	tot++;
	int ans=INF;
	while(1){
		if(tot==26){
			ans=min(ans,r-l+1);
		}
		if(r<=s.size()-2){			
			r++;
			v[s[r]]++;
			if(v[s[r]]==1)	tot++;
		}
		if(tot==26){
			ans=min(ans,r-l+1);
		}
		while(l<r){
			if(v[s[l]]==1)	break;
			v[s[l]]--;
			l++;
		}
		if(tot==26){
			ans=min(ans,r-l+1);
		}
		if(r==s.size()-1){
			while(l<r && tot==26){
				ans=min(ans,r-l+1);
				v[s[l]]--;
				if(v[s[l]]==0)	tot--;
			}
			break;
		}
	}
	if(ans!=INF)	cout<<ans;
	else	cout<<"QwQ";
	return 0;
}
posted @   Cap1taL  阅读(91)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示