11536 - Smallest Sub-Array(滑动窗口)

来源:互联网 发布:论文数据自己瞎编的 编辑:程序博客网 时间:2024/05/16 19:17

该题其实就是lrj讲的滑动窗口的一个小小变形, 只不过这个窗口的大小是可变的 。  具体方法其实和例题Shuffle类似,用首尾两个指针维护窗口,用一个数组cnt记录1~k中每个数字在窗口中出现的次数,用一个变量c记录窗口中只出现了一次的数字的个数 。   这样只要c == k 这就是一个满足条件的答案,取最小答案即可 。

由于每个元素都只插入删除一次,所以时间复杂度为O(n)。

该算法还有一个名字叫“取尺法” ,特点是处理一段长度未知的连续区间,通过反复地推进区间的开头和末尾 ,直到得出答案的方法 。

细节参见代码:

#include<bits/stdc++.h>using namespace std;const int maxn = 1000000 + 10;int T,n,m,k,Case = 0,a[maxn],cnt[maxn];map<int,int> p;vector<int> g[105];int main() {    scanf("%d",&T);    while(T--) {        scanf("%d%d%d",&n,&m,&k);        memset(cnt,0,sizeof(cnt));        a[1] = 1; a[2] = 2; a[3] = 3;        if(n>3) for(int i=4;i<=n;i++) {            a[i] = (a[i-1]+a[i-2]+a[i-3])%m + 1;        }        int ans = 2000000000;        int rear = 0,last = 1,c = 0;        while(true) {            if(c == k) {                cnt[a[last]] -- ;                if(cnt[a[last]] == 0 && a[last] <= k) c--;                last++;                if(c == k) ans = min(ans , rear - last + 1);            }            else {                rear ++;                if(rear > n) break;                cnt[a[rear]]++;                if(cnt[a[rear]] == 1 && a[rear] <= k) c++;                if(c == k) ans = min(ans , rear - last + 1);            }        }        printf("Case %d: ",++Case);        if(ans != 2000000000) printf("%d\n",ans);        else printf("sequence nai\n");    }    return 0;}


1 0
原创粉丝点击