1. 程式人生 > >字串 (包含T全部元素的最小視窗)

字串 (包含T全部元素的最小視窗)

題目描述

小N現在有一個字串S。他把這這個字串的所有子串都挑了出來。一個S的子串T是合法的,當且僅當T中包含了所有的小寫字母。小N希望知道所有的合法的S的子串中,長度最短是多少。

輸入描述:

一行一個字串S。只包含小寫字母。S的長度不超過106.

輸出描述:

一行一個數字,代表最短長度。資料保證存在一個合法的S的子串。

示例1

輸入

複製

ykjygvedtysvyymzfizzwkjamefxjnrnphqwnfhrnbhwjhqcgqnplodeestu

輸出

複製

49

時間複雜度和空間複雜度,都是極佳的

1.一開始二分+暴力列舉  TLE,2.開始維護26個字元的樹狀陣列,直接O(log(n)))

, MLE ,直接崩潰

應該是雙指標,這種思想還是蠻普遍的,找到最右邊的合法點,然後不斷的縮。

轉載連結

#include<bits/stdc++.h>
using namespace std;

#define rep(i,a,b) for(int i=a;i<b;i++)

const int N=1e6+10;
char s[N];

int need_find[256],has_find[256];

int min_win(int slen)
{
    rep(i,0,26)need_find[i+'a']++;

    int ans=slen;
    int res=0,tlen=26;
    for(int p1=0,p2=0;p2<slen;p2++){
        if(!need_find[s[p2]])continue;

        has_find[s[p2]]++;
        if(has_find[s[p2]]<=need_find[s[p2]]) ++res;

        if(res==tlen){
            while(p1<=p2&&has_find[s[p1]]>need_find[s[p1]]){
                has_find[s[p1]]--;
                if(!has_find[s[p1]])--res;
                ++p1;
            }
            ans=min(ans,p2-p1+1);
        }
    }
    return ans;
}

int main()
{
    scanf("%s",s);
    int len=strlen(s);

    int ans=min_win(len);
    printf("%d\n",ans);

    return 0;
}