目录
这是c语言风格代码,也就是通过数组来模拟这件事,思路与上面一样,我们是通过数组来完成这件事
思路是一样的,数组模拟只是加了个下标数组min[],还有max[]
如果你觉得本文还可以,请留下你的赞,谢谢!(这是我第二次学习单调队列可以说是复习)
我之前是通过看视频,还有代码网站学会的,个人觉得还不错,非常推荐
单调队列正式登场!| LeetCode:239. 滑动窗口最大值_哔哩哔哩_bilibili
代码网站
https://zhuanlan.zhihu.com/p/437438743
单调队列(超级详细讲解)//这是我的语雀,但是复制过来字体的颜色不见了,后面手动加了点
单调队列定义:
顾名思义,单调队列的重点分为「单调」和「队列」。
「单调」指的是元素的「规律」——递增(或递减)。
「队列」指的是元素只能从队头和队尾进行操作。
单调队列分两种
一种是单调递增的,另外一种是单调递减的。
解题模板
题意分析:主要是寻找滑动窗口的最大值与最小值
此题核心代码分三步走:
1.记得写输入还有题意的答案递推代码
qmax.push_back(i);
if (i >= k)cout << a[qmax.front()] << " ";
2. 维护窗口的大小
(这个一般是与双端队列的头部比较)弹出的一般也是头部)
如果队列中的某个元素的下标 qmin[head_min] 小于等于 i - k,说明这个元素已经不在当前窗口内,需要被移除。
while (!qmin.empty() && qmax.front() <= i - k) {
qmax.pop_front();
}
3移除尾部元素
(如果当前滑动窗口是求最小值)
如果队列不为空且当前元素与队尾元素小,移除窗口中比首元素大的
(如果当前滑动窗口是求最大值)
如果队列不为空且当前元素与队尾元素大,移除窗口中比首元素小的
//窗口 1 2 5 来了一个3变成 1 2 3 (这里是求最大值)
while (!qmax.empty() && a[qmax.back()] <= a[i]) {
qmax.pop_back();
}
洛谷原题
P1886 滑动窗口 /【模板】单调队列
模拟双端队列也就是窗口的移动过程
单调队列解题思路
该类型多半采用单调队列,暴力容易超时,当时暴力写出来超时,才来用单调队列
主要是理解窗口移动元素也就是双端队列移动
本来本文是打算插入动画的,但是我没有语雀的会员插入不了,抱歉了,各位大佬
下面这是个博主实操演示过程
链接单调队列正式登场!| LeetCode:239. 滑动窗口最大值_哔哩哔哩_bilibili
题意分析:主要是寻找滑动窗口的最大值与最小值
此题核心代码分三步走:
1.记得写输入还有题意的所需要的答案
qmax.push_back(i);//输入
if (i >= k)cout << a[qmax.front()] << " ";//
2. 维护窗口的大小
(这个一般是与双端队列的头部比较)弹出的一般也是头部)
如果队列中的某个元素的下标 qmin[head_min] 小于等于 i - k,说明这个元素已经不在当前窗口内,需要被移除。
while (!qmin.empty() && qmin.front() <= i - k) {
qmin.pop_front();
}
3移除尾部元素
(如果当前滑动窗口是求最小值)如果队列不为空且当前元素与队尾元素小,移除队尾元素
(如果当前滑动窗口是求最大值)如果队列不为空且当前元素与队尾元素大,移除队尾元素
//窗口 1 2 5 来了一个3变成 1 2 3
while (!qmin.empty() && a[qmin.back()] >= a[i]) {
qmin.pop_back();
}
这是c++风格代码
c++主要思路是通过窗口期的头尾判断来解决这个问题,,max窗口期的前面是最大值,min窗口期的前面是最小值
窗口期的后面要与a[i]作比较
#include<bits/stdc++.h>
using namespace std;
const int ma = 1000005;
int n, k;
int a[ma];
deque<int>qmin, qmax;
int main() {
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
//按下标来,if数组首地址小于等于i-k即0即,当前元素不在窗口期
while (!qmin.empty() && qmin.front() <= i - k) {
qmin.pop_front();
}
//窗口 1 2 5 来了一个3变成 1 2 3
while (!qmin.empty() && a[qmin.back()] >= a[i]) {
qmin.pop_back();
}
qmin.push_back(i);
if (i >= k) cout << a[qmin.front()] << " ";
}
cout << endl;
for (int i = 1; i <= n; i++) {
//不在窗口期的丢了
while (!qmax.empty() && qmax.front() <= i - k) {
qmax.pop_front();
}
//移除队列中比首元素小的
while (!qmax.empty() && a[qmax.back()] <= a[i]) {
qmax.pop_back();
}
qmax.push_back(i);
if (i >= k)cout << a[qmax.front()] << " ";
}
return 0;
}
这是c语言风格代码,也就是通过数组来模拟这件事,思路与上面一样,我们是通过数组来完成这件事
思路是一样的,数组模拟只是加了个下标数组min[],还有max[]
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define ma 1000003
int n, a[ma], t, h, k, min[ma], max[ma];
//min求最小值的所有
//max求最大值的所有
int main() {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
h = t = 1;
//h min//头指针
//t max//尾指针
for (int i = 1; i <= n; i++) {
//当前首元素不在窗口期
if (h < t && min[h] <= i - k) {
h++;
}
//窗口期 125 123
while (h<t && a[min[t - 1]]>=a[i]) {
t--;
}
min[t++] = i;
if (i >= k)printf("%d ", a[min[h]]);
}
printf("\n");
h = t = 1;
for (int i = 1; i <= n; i++) {
if (h < t && max[h] <= i - k) {
h++;
}
while (h < t && a[max[t-1]] <= a[i]) {
t--;
}
max[t++] = i;
if (i >= k)printf("%d ", a[max[h]]);
}
return 0;
}