链接:https://www.nowcoder.com/acm/contest/161/A
来源:牛客网
题目描述
小N现在有一个字符串S。他把这这个字符串的所有子串都挑了出来。一个S的子串T是合法的,当且仅当T中包含了所有的小写字母。小N希望知道所有的合法的S的子串中,长度最短是多少。
输入描述:
一行一个字符串S。只包含小写字母。S的长度不超过106.
输出描述:
一行一个数字,代表最短长度。数据保证存在一个合法的S的子串。
示例1
输入
复制
ykjygvedtysvyymzfizzwkjamefxjnrnphqwnfhrnbhwjhqcgqnplodeestu
输出
复制
49

作弊签到了一题…..
赛中问大佬的,学了最小覆盖子串这个问题
代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=105;
//最小满足条件的子串长度
char s[N];
char t[N];
//目标串和原串每个字母出现的次数,这里考虑26个小写字母
int sHash[26];
int tHash[26];
int main(void){
    int tlen=strlen(t);
    int slen=strlen(s);
    //预处理目标字符串的hash数组
    for(int i=0;i<tlen;i++){
        tHash[t[i]-'a']++;
    }
    //临时的字符串起点
    int ss=0;
    int found=0;
    //子串的起点和终点
    int start=-1;
    int end=slen;
    int minLen=slen;
    for(int i=0;i<slen;i++){
        sHash[s[i]-'a']++;
        //加后出现次数不大于目标串该字符的出现次数,即找到一个匹配字符
        //比如t是aab 当s是aaa时找到前两个a时found++,第三个a则不会
        if(sHash[s[i]-'a']<=tHash[s[i]-'a']){
            found++;
        }
        //找到符合要求的子串
        if(found==tlen){
            //将子串开头没用的跳过(没用指该字符出现次数任大于目标串中该字符出现次数
            //因此删去也不影响)
            while(ss<i && sHash[s[ss]-'a']>tHash[s[ss]-'a']){
                sHash[s[ss]-'a']--;
                //起点加1
                ss++;
            }
            //更新答案
            if(i-ss<minLen){
                minLen=i-ss+1;
                start=ss;
                end=i;
            }
            //删去开头,匹配字符数记得减1(因为经过前面的操作这里的开头肯定是有用的)
            sHash[s[ss]-'a']--;
            found--;
            ss++;
        }
    }
    return 0;
}

然后赛后看了代码发现更简单,不过原理是一样的
代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=1e6+10;
char s[N];
int a[N];
int main(void){
    scanf("%s",s);
    int l=strlen(s);
    //匹配的字符数
    int num=0;
    int ans=0x3f3f3f3f;
    for(int i=0,j=0;i<l;i++){
        if(!a[s[i]-'a']){
            num++;
        }
        a[s[i]-'a']++;
        while(num==26){
            ans=min(ans,i-j+1);
            a[s[j]-'a']--;
            //子串开头字符删掉有影响
            if(!a[s[j++]-'a']){
                num--;
                break;
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}