当前位置:   article > 正文

洛谷:P1886 滑动窗口 之 (彻底搞懂单调队列)_滑动窗口洛谷

滑动窗口洛谷

传送门:P1886 滑动窗口 /【模板】单调队列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1886

一、题目描述

664b9239def04943b94182a254b0e879.png

 

二、思路

滑动窗口求m区间内的最小值的求解过程一样,都是运用单调队列求解,当然也可以运用其他方法求解,滑动窗口比起求m区间内的最小值多了个求最大值,那我们可以写两个函数,一个求最小值,一个求最大值,函数总的内容是一样的,只需要修改队尾的判断条件,具体求解过程请参考求m区间内的最小值

洛谷:P1440 求m区间内的最小值_´悠 子ᴗ`-_-╭☞ꪗꪖꪑ的博客-CSDN博客

下面我们来了解什么是单调队列:


单调队列,顾名思义,是一种具有单调性的队列。众所周知,单调性有单调递增和单调递减两种,相应的单调队列也分为单调递增队列和单调递减队列两种。

单调递增队列:保证队列头元素一定是当前队列的最小值,用于维护区间的最小值。

单调递减队列:保证队列头元素一定是当前队列的最大值,用于维护区间的最大值。

实现流程:


实现单调队列,主要分为三个部分:

去尾操作 :队尾元素出队列。当队列有新元素待入队,需要从队尾开始,删除影响队列单调性的元素,维护队列的单调性。(删除一个队尾元素后,就重新判断新的队尾元素)
去尾操作结束后,将该新元素入队列。

删头操作 :队头元素出队列。判断队头元素是否在待求解的区间之内,如果不在,就将其删除。(这个很好理解呀,因为单调队列的队头元素就是待求解区间的极值)

取解操作 :经过上面两个操作,取出 队列的头元素 ,就是 当前区间的极值 。

题解:


题目要我们求得极大值和极小值,那我们可以用一个单调递增队列和一个单调递减队列分别去维护k区间内的最大值和最小值。

下面来演示一下具体过程:

如案例 n=8,k=3 {1,3,-1,-3,5,3,6,7}

先求k区间的极大值

  1. void max_windows() //找k区间内最大值
  2. {
  3. front = 1;
  4. rear = 0;
  5. for (int i = 1; i <= n; i++)
  6. {
  7. while (q[front] <= i - k && front <= rear) //保证队首在k区间
  8. front++;
  9. while (front <= rear && a[q[rear]] <= a[i]) //维护k区间的单调性
  10. rear--;
  11. q[++rear] = i; //入队
  12. if (i >= k)
  13. cout << a[q[front]] << " ";
  14. }
  15. cout << endl;
  16. }

 

队列中情况队列进行的操作Min
1队列为空,1入队...
1 33<1,3入队...
 -1-1<3,1,3和1出队,-1入队-1
-3-3<-1,-1出队,-3入队-3
-3 55>-3,5入队-3
-3,33<-3,3入队-3
..........................

再求k区间极小值:

  1. void min_windows() //找k区间内最小值
  2. {
  3. front = 1;
  4. rear = 0;
  5. for (int i = 1; i <= n; i++)
  6. {
  7. while (q[front] <= i - k && front <= rear) //保证队首在k区间
  8. front++;
  9. while (front <= rear && a[q[rear]] >= a[i]) //维护k区间的单调性
  10. rear--;
  11. q[++rear] = i; //入队
  12. if (i >= k)
  13. cout << a[q[front]] << " ";
  14. }
  15. cout << endl;
  16. }
队列中情况队列进行的操作Max
1队列为空,1入队...
33>1,1出队,3入队...
3 -1-1<3,-1入队3
3 -1 -3-3<-1,-3入队3
53超出k区间,3入队,5>-1,-3,-1,-3出队,5入队5
5,33<5,3入队5
..........................

从上面求极大值和极小值的表格可以看出,单调队列不仅维护了区间k单调性,还实现了,队首就是要找的极大值或极小值。

三、代码区

  1. #include <iostream>
  2. using namespace std;
  3. int q[1000005], a[1000005], front, rear, n, k;
  4. void max_windows() //找k区间内最大值
  5. {
  6. front = 1;
  7. rear = 0;
  8. for (int i = 1; i <= n; i++)
  9. {
  10. while (q[front] <= i - k && front <= rear) //保证队首在k区间
  11. front++;
  12. while (front <= rear && a[q[rear]] <= a[i]) //维护k区间的单调性
  13. rear--;
  14. q[++rear] = i; //入队
  15. if (i >= k)
  16. cout << a[q[front]] << " ";
  17. }
  18. cout << endl;
  19. }
  20. void min_windows() //找k区间内最小值
  21. {
  22. front = 1;
  23. rear = 0;
  24. for (int i = 1; i <= n; i++)
  25. {
  26. while (q[front] <= i - k && front <= rear) //保证队首在k区间
  27. front++;
  28. while (front <= rear && a[q[rear]] >= a[i]) //维护k区间的单调性
  29. rear--;
  30. q[++rear] = i; //入队
  31. if (i >= k)
  32. cout << a[q[front]] << " ";
  33. }
  34. cout << endl;
  35. }
  36. int main()
  37. {
  38. cin >> n >> k;
  39. for (int i = 1; i <= n; i++)
  40. {
  41. cin >> a[i];
  42. }
  43. min_windows();
  44. max_windows();
  45. return 0;
  46. }

 90a1d660d6424c48b228d50e20dc6ca2.png

     如果有什么不懂的地方可以在评论区留言!

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/993854
推荐阅读
  

闽ICP备14008679号