赞
踩
滑动窗口和求m区间内的最小值的求解过程一样,都是运用单调队列求解,当然也可以运用其他方法求解,滑动窗口比起求m区间内的最小值多了个求最大值,那我们可以写两个函数,一个求最小值,一个求最大值,函数总的内容是一样的,只需要修改队尾的判断条件,具体求解过程请参考求m区间内的最小值。
洛谷:P1440 求m区间内的最小值_´悠 子ᴗ`-_-╭☞ꪗꪖꪑ的博客-CSDN博客
单调队列,顾名思义,是一种具有单调性的队列。众所周知,单调性有单调递增和单调递减两种,相应的单调队列也分为单调递增队列和单调递减队列两种。
单调递增队列:保证队列头元素一定是当前队列的最小值,用于维护区间的最小值。
单调递减队列:保证队列头元素一定是当前队列的最大值,用于维护区间的最大值。
去尾操作 :队尾元素出队列。当队列有新元素待入队,需要从队尾开始,删除影响队列单调性的元素,维护队列的单调性。(删除一个队尾元素后,就重新判断新的队尾元素)
去尾操作结束后,将该新元素入队列。
删头操作 :队头元素出队列。判断队头元素是否在待求解的区间之内,如果不在,就将其删除。(这个很好理解呀,因为单调队列的队头元素就是待求解区间的极值)
取解操作 :经过上面两个操作,取出 队列的头元素 ,就是 当前区间的极值 。
下面来演示一下具体过程:
如案例 n=8,k=3 {1,3,-1,-3,5,3,6,7}
先求k区间的极大值
void max_windows() //找k区间内最大值 { front = 1; rear = 0; for (int i = 1; i <= n; i++) { while (q[front] <= i - k && front <= rear) //保证队首在k区间 front++; while (front <= rear && a[q[rear]] <= a[i]) //维护k区间的单调性 rear--; q[++rear] = i; //入队 if (i >= k) cout << a[q[front]] << " "; } cout << endl; }
队列中情况 | 队列进行的操作 | Min |
1 | 队列为空,1入队 | ... |
1 3 | 3<1,3入队 | ... |
-1 | -1<3,1,3和1出队,-1入队 | -1 |
-3 | -3<-1,-1出队,-3入队 | -3 |
-3 5 | 5>-3,5入队 | -3 |
-3,3 | 3<-3,3入队 | -3 |
..... | ................ | ..... |
再求k区间极小值:
- void min_windows() //找k区间内最小值
- {
- front = 1;
- rear = 0;
- for (int i = 1; i <= n; i++)
- {
- while (q[front] <= i - k && front <= rear) //保证队首在k区间
- front++;
- while (front <= rear && a[q[rear]] >= a[i]) //维护k区间的单调性
-
- rear--;
- q[++rear] = i; //入队
- if (i >= k)
- cout << a[q[front]] << " ";
- }
- cout << endl;
- }

队列中情况 | 队列进行的操作 | Max |
1 | 队列为空,1入队 | ... |
3 | 3>1,1出队,3入队 | ... |
3 -1 | -1<3,-1入队 | 3 |
3 -1 -3 | -3<-1,-3入队 | 3 |
5 | 3超出k区间,3入队,5>-1,-3,-1,-3出队,5入队 | 5 |
5,3 | 3<5,3入队 | 5 |
..... | ................ | ..... |
从上面求极大值和极小值的表格可以看出,单调队列不仅维护了区间k单调性,还实现了,队首就是要找的极大值或极小值。
三、代码区
- #include <iostream>
- using namespace std;
- int q[1000005], a[1000005], front, rear, n, k;
-
- void max_windows() //找k区间内最大值
- {
- front = 1;
- rear = 0;
- for (int i = 1; i <= n; i++)
- {
- while (q[front] <= i - k && front <= rear) //保证队首在k区间
- front++;
- while (front <= rear && a[q[rear]] <= a[i]) //维护k区间的单调性
- rear--;
- q[++rear] = i; //入队
- if (i >= k)
- cout << a[q[front]] << " ";
- }
- cout << endl;
- }
-
- void min_windows() //找k区间内最小值
- {
- front = 1;
- rear = 0;
- for (int i = 1; i <= n; i++)
- {
- while (q[front] <= i - k && front <= rear) //保证队首在k区间
- front++;
- while (front <= rear && a[q[rear]] >= a[i]) //维护k区间的单调性
-
- rear--;
- q[++rear] = i; //入队
- if (i >= k)
- cout << a[q[front]] << " ";
- }
- cout << endl;
- }
- int main()
- {
- cin >> n >> k;
- for (int i = 1; i <= n; i++)
- {
- cin >> a[i];
- }
- min_windows();
- max_windows();
- return 0;
- }

如果有什么不懂的地方可以在评论区留言!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。