【演算法學習】尺取法

Keane1998發表於2019-08-15

基礎模板

求和大於等於S的最小子段

ll sum=0;
int l=1,r=1;
while(true){
    //全速推進r指標
    while(r<=n && sum<s){
        sum+=a[r++];
    }
    //r走到頭,sum無法再增大,答案無法更優
    if(sum<s){
        break;
    }
    //更新答案
    ans=min(ans,r-l);
    //龜速推進l指標
    sum-=a[l++];
}

例題

POJ3061

即上面模板題

HDU5672

題意

給定一個字串,要求出不同字元個數大於等於k的子串個數。

分析

  • 跟不同數/字母個數相關的也是常用到尺取法。
  • 一樣的套路,先全速推進r,字元出現次數計數並更新不同字元個數,然後累計答案,龜速推進l。

程式碼

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+50;
char s[N];
int T,k;
int cnt[30];
int main(){
//    freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--){
        memset(cnt,0,sizeof(cnt));
        scanf("%s",s+1);
        scanf("%d",&k);
        int n=strlen(s+1);
        ll ans=0;
        int num=0;
        int l=1,r=1;
        while(true){
            while(r<=n && num<k){
                cnt[s[r]-'a']++;
                if(cnt[s[r]-'a']==1){
                    num++;
                }
                r++;
            }
            if(num<k){
                break;
            }
            ans+=(n-(r-1)+1);
            cnt[s[l]-'a']--;
            if(cnt[s[l]-'a']==0){
                num--;
            }
            l++;
            if(l>r){
                r=l+1;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

HDU5056

題意

給定一個字串,要求出串內所有字元出現次數都小於等於k的子串個數。

分析

  • 同樣是尺取法的思想,不過寫法略微不同。
  • \(cnt\)同樣是維護當前區間每種字母的個數,全速推進\(r\),沒加入一個字元\(s[r]\),如果\(cnt[s[r]-'a']<=k\),就直接累計答案,否則,刪除該字元,\(r\)回退,然後推進\(l\)

程式碼

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+50;
char s[N];
int T,k;
int cnt[30];
int main(){
//    freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--){
        memset(cnt,0,sizeof(cnt));
        scanf("%s",s+1);
        scanf("%d",&k);
        int n=strlen(s+1);
        ll ans=0;
        int l=1,r=1;
        while(l<=n){
            while(r<=n){
                cnt[s[r]-'a']++;
                if(cnt[s[r]-'a']<=k){
                    ans+=r-l+1;
                    r++;
                }else{
                    cnt[s[r]-'a']--;
                    break;
                }
            }
            cnt[s[l]-'a']--;
            l++;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

相關文章