ac 154. 滑动窗口

如果用普通窗口 每一次往右边移动一格(时间n)进行一次判断(时间k)需要 nk 的时间复杂度

用排序好的窗口, 比如一开始输入

8 3
1 3 -1 -3 5 3 6 7

先是 1 这个数字再窗口内, 然后 由于第二个数字 3比1要小所以不记录队列中
再是 -1 这个数字 比1小所以记录 此时队列为 [1 ,-1](当然是用数组的下标来标记实际上是 [0, 1]
再下一个数字同理 1, -1, -3
再下一个数字 此时 由于大于 了窗口长度 所以先把 1 去除 变成 [-1, -3](实际[1, 2])
再比较 5 这个数字 由于比-3要大所以不记录,如此一直比较。
当i的大小大于窗口长度就可以开始输出了

输出最大值同理

      // 常见模型:找出滑动窗口中的最大值/最小值
        // int hh = 0, tt = -1;
        // for (int i = 0; i < n; i ++ )
        // {
        //     while (hh <= tt && check_out(q[hh])) hh ++ ;  // 判断队头是否滑出窗口
        //     while (hh <= tt && check(q[tt], i)) tt -- ;
        //     q[ ++ tt] = i;
        // }
        #include<bits/stdc++.h>
        using namespace std;

        const int N=1000010;
        int q[N], a[N];
        int main() {
            int n, k;
            cin >> n >> k;
            for (int i = 0; i < n; i ++) {
                cin >> a[i];
            }
            int hh = 0, tt = -1;
            // i 本质是窗口的依次经历的右端点
            for (int i = 0; i < n; i ++ )
            {
                // 当前窗口区间是[i - k + 1, i]
                if (hh <= tt && q[hh] < i - k + 1) hh ++; //队首小于当前窗口最左边就舍去
                while (hh <= tt && a[q[tt]] >= a[i]) tt -- ;  //队尾(左为首,右为尾)大于当前的元素,那么他一定不会被当成最小值输出,就删掉
                q[ ++ tt] = i;//再加当前的数字
                
                if(i >= k - 1) printf("%d ", a[q[hh]]);
            }
            
            puts("");
            
            hh = 0, tt = -1;
            for (int i = 0; i < n; i ++ )
            {
                if (hh <= tt && q[hh] < i - k + 1) hh ++; 
                while (hh <= tt && a[q[tt]] <= a[i]) tt -- ;  
                q[ ++ tt] = i;
                
                if(i >= k - 1) printf("%d ", a[q[hh]]);
            }
            puts("");
            return 0;
            
        }
posted @ 2022-09-12 17:01  天然气之子  阅读(16)  评论(0编辑  收藏  举报