滑动窗口(单调队列)

基本概念:

滑动窗口是以指针为基础的一种思想,两个指针之间形成的集合形成了一个窗口。

例题

describe

给定一个大小为n≤1e6 的数组。

有一个大小为 k 的滑动窗口,它从数组的最左边移动到最右边。

你只能在窗口中看到 k 个数字。

每次滑动窗口向右移动一个位置。

你的任务是确定滑动窗口位于每个位置时,窗口中的最大值和最小值。

分析:

以寻找窗口中的最大值为例

1.窗口的长度为k,我们要找的是窗口中的最大(小)值,且每找到一个窗口会向右移动一个单位

2.我们可以构造一个队列q[ ],以入列和出列的方式模拟窗口的移动。

3.我们发现每当窗口向右移动时我们可以先判断新加进的数是否符合条件,比如说,若目前队尾数为3准备加进来的数为4,那么3就不可能是窗口中的最大值了(鞠躬尽瘁),直接把3踢掉就好了让4替代他的位置;但若加紧来的数比队尾数要小,那么它还是有可能比后边即将加进来的数大的(所以该留下他给他机会让他表现表现)

OK上代码;

#include<iostream>
using namespace std;
int arr[1000001];
int dui1[100001], dui2[100000];
int h = 1, r = 0;
int n, m;
void Max() {
	h = 1, r = 0;//h队首,l队尾
	for (int i = 1; i <= n; i++) {
		while (h <= r && i - dui1[h] >= m)
			h++;//查看当前下标和对手下标之间的数是否超过窗口宽度m,如果超过就把队首向右移动
		while (h <= r && arr[i] >= arr[dui1[r]])
			r--;//查看新来的是否比队尾的数小,如果是那就不用进来了,反正他不可能是最大那个,若比队尾的数大那就把队尾换成它反正队尾不可能是最大的可以退休了
		dui1[++r] = i;//储存当前队尾的下标
		if (i >= m)cout << arr[dui1[h]] << " ";//输出队首
	}
}
void Min()
{
	h = 1, r = 0;
	for (int i = 1; i <= n; i++) {
		while (h <= r && i - dui2[h] >= m)
			h++;
		while (h <= r && arr[i] <= arr[dui2[r]])//唯一改变的就这个比较大小符号
			r--;
		dui2[++r] = i;
		if (i >= m)cout << arr[dui2[h]] << " ";
	}
}
int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		cin >> arr[i];
	Min();
	cout << endl;
	Max();
	return 0;
}

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值