附上题目链接:点击这里

题意:

给你一个长度为 n 的数组 , 再给你一个只能看见 k 个数字的窗口 , 现在把这个窗口放在数组上从左到右依次滑动 , 求出每滑动一次时窗口可见的数字中的最大值和最小值。

注意这一题的数据范围是1e6 , 因此暴力是不可能的 ;

这时要用到单调队列。(就是维护一个单调的序列)

举个例子:

数列为:6 4 10 10 8 6 4 2 12 14
N=10,K=3;
那么我们构造一个长度为3的单调递减队列:
首先,那6和它的位置0放入队列中,我们用(6,0)表示,每一步插入元素时队列中的元素如下
插入6:(6,0);
插入4:(6,0),(4,1);
插入10:(10,2);
插入第二个10,保留后面那个:(10,3);
插入8:(10,3),(8,4);
插入6:(10,3),(8,4),(6,5);
插入4,之前的10已经超出范围所以排掉:(8,4),(6,5),(4,6);
插入2,同理:(6,5),(4,6),(2,7);
插入12:(12,8);
插入14:(14,9);
那么f(i)就是第i步时队列当中的首元素:6,6,10,10,10,10,8,6,12,14
同理,最小值也可以用单调队列来做。

大致就是这样的一个思路 ,下面代码?(唉~感觉自己可敷衍了 , 对不起今晚吃的肉和雪碧)

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
const int maxn = 1010000;
using namespace std;
int a[maxn] , mx[maxn] , mn[maxn] , n , m;
struct node
{
	int x , y;//值与下标 
}v[maxn];
void getmax()//下标从1 开始 
{
	int head = 1 , tail = 0;
	for(int i = 1 ; i < m ; i++)
	{
		while(head <= tail && v[tail].x < a[i]) tail--;
		v[++tail].x = a[i];v[tail].y = i;
	}
	for(int i = m ; i <= n ; i++)
	{
		while(head <= tail && v[tail].x < a[i]) tail--;
		v[++tail].x = a[i];v[tail].y = i;
		while(v[head].y < (i-m+1)) head++;
		mx[i-m+1] = v[head].x;
	}
} 
void getmin()
{
	int head = 1 , tail = 0;
	for(int i = 1 ; i < m ; i++)
	{
		while(head <= tail && v[tail].x >= a[i]) tail--;
		v[++tail].x = a[i];v[tail].y = i;
	}
	for(int i = m ; i <= n ; i++)
	{
		while(head <= tail && v[tail].x >= a[i]) tail--;
		v[++tail].x = a[i];v[tail].y = i;
		while(v[head].y < (i-m+1))head++;
		mn[i-m+1] = v[head].x;
	}
}
int main()
{
	scanf("%d %d" , &n , &m);
	for(int i = 1 ; i <= n ; i++)
	{
		scanf("%d" , &a[i]);
	}
	getmin();
	getmax();
	for(int i = 1 ; i <= n-m+1 ; i++)
	{
		if(i==1)printf("%d",mn[i]);
        else printf(" %d",mn[i]);
	 } 
	 printf("\n");
	 for(int i = 1 ; i <= n-m+1 ; i++)
	 {
	 	if(i==1)printf("%d",mx[i]);
        else printf(" %d",mx[i]);
	 }
	 printf("\n");
	return 0;
 }