51nod-1127 最短的包含字符串(尺取法)
1127 最短的包含字符串
给出一个字符串,求该字符串的一个子串s,s包含A-Z中的全部字母,并且s是所有符合条件的子串中最短的,输出s的长度。如果给出的字符串中并不包括A-Z中的全部字母,则输出No Solution。
输入
第1行,1个字符串。字符串的长度 <= 100000。
输出
输出包含A-Z的最短子串s的长度。如果没有符合条件的子串,则输出No Solution。
输入样例
BVCABCDEFFGHIJKLMMNOPQRSTUVWXZYZZ
输出样例
28
本题要求输出A-Z的最短区间子串s的长度,可以使用尺取法(即双指针)法写题,该算法的复杂度是O(n),尺取法即设置两个变量指向一前一后,遍历数组即可,贴AC代码
#include <bits/stdc++.h>
using namespace std;
string str;
int cnt[30];
const int _max=1e5+5;
int main()
{
int start=0,t=0;
int ans=_max;
cin>>str;
memset(cnt,0,sizeof(cnt));
for(int i=0;i<str.length();i++)
{
int c=str[i]-'A';
if(!cnt[c])
t++;
cnt[c]++;
while(cnt[str[start]-'A']>1)
cnt[str[start]-'A']--,start++;
if(t==26)
ans=min(ans,i-start+1);
}
if(t<26)
cout<<"No Solution"<<endl;
else
cout<<ans<<endl;
return 0;
}
题解:开始定义start,即后面的指针,t=0,t是区间长度的计数器,ans是区间长度,也就是答案,因为要对ans和长度取最小值,所以一开始ans直接设max,cnt即计数器数组,他的下标0-25记录的是字母A-Z出现的次数,首先将cnt数组全部置0,输入字符串。在for循环中,刚开始的cnt计数器数组,如果cnt[i]的值为0,就说明编号为i+1的字母没出现过,t++,并且当前的编号为i+1的下标加一,当走到第一while语句时,开始判断start,即第一个指针,cnt数组中start指向的元素是不是出现了一次以上,如果是,则cnt[str[start]-‘A’]减一,并且指针后移,走到 i f 时,判断26个字母是不是都出现过了,如果都出现过,则开始取ans和区间长度(i-start+1)的最小值。退出循环,若t<26,则说明26个字母没有都出现过,输出No Solution,反之输出ans。