滑动窗口.

1:滑动窗口
查看提交统计提问
总时间限制: 12000ms 内存限制: 65536kB
描述
给定一个长度为n(n<=10^6)的数组。有一个大小为k的滑动窗口从数组的最左端移动到最右端。你可以看到窗口中的k个数字。窗口每次向右滑动一个数字的距离。
下面是一个例子:
数组是 [1 3 -1 -3 5 3 6 7], k = 3。

窗口位置 最小值 最大值
[1 3 -1] -3 5 3 6 7 -1 3
1 [3 -1 -3] 5 3 6 7 -3 3
1 3 [-1 -3 5] 3 6 7 -3 5
1 3 -1 [-3 5 3] 6 7 -3 5
1 3 -1 -3 [5 3 6] 7 3 6
1 3 -1 -3 5 [3 6 7] 3 7
你的任务是得到滑动窗口在每个位置时的最大值和最小值。
输入
输入包括两行。
第一行包括n和k,分别表示数组的长度和窗口的大小。
第二行包括n个数字。
输出
输出包括两行。
第一行包括窗口从左至右移动的每个位置的最小值。
第二行包括窗口从左至右移动的每个位置的最大值。
在这里插入图片描述
思路:不能采用直接比较的方法,会超出时间限制。要使用优先对列来实现。
以求最小值为例,维护这样一个队列:
1.队列中元素保存数列下标,数列中元素(下标)递增,并且下标对应数列中元素(下标对应值)也递增。
显然我们i从0开始遍历保证了队列中保存的下标是递增的,我们只需要设计算法保证下标对应数列中元素也递增即可。
2.加入一个下标时,从后往前删掉所有对应值大于当前下标对应值的下标,使得下标对应元素也能递增。
3.将这个下标加入队列
4.如果队列首位元素在后面不再需要用到了,队列首位后移一位。

#include<iostream>
using namespace std;
int n, k;
int a[1000000], b[1000000];

void min()
{
	int uut = 1, r = 0;
	for (int i = 1; i <= n; i++) {
		while (r >= uut && a[b[r]] >= a[i])//加入新下标,先从后往前删除所有大于的元素下标
			r--;

		b[++r] = i;
		if (b[r] - b[uut] + 1 > k) //b[uut]存放最小值的下标
			uut++;


		if (i >= k) //输出
			cout<<a[b[uut]]<<" ";
	}
	cout << endl;
}
void max()
{
	int l = 1, r = 0;
	for (int i = 1; i <= n; i++) {
		while (r >= l && a[b[r]] <= a[i])
			r--;
		b[++r] = i;
		if (b[r] - b[l] + 1 > k) 
			l++;
		if (i >= k) 
			cout << a[b[l]] << " ";
	}
	cout << endl;
}
int main()
{
	cin >>n >> k;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
	}
	min();
	max();
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值