GDUT_22级寒假训练专题一 I滑动窗口

文章描述了一个编程问题,要求通过滑动窗口算法,在一个数组中找出每个位置时窗口内的最大值和最小值。解决方案利用单调栈,维护最大值和最小值栈,当新元素进入窗口时,更新栈以保持单调性,从而在O(n)时间内求解问题。
摘要由CSDN通过智能技术生成

题目描述

原题来自:POJ 2823

给一个长度为 N 的数组,一个长为 K 的滑动窗体从最左端移至最右端,你只能看到窗口中的 K 个数,每次窗体向右移动一位,如下图:

|窗口位置|最小值|最大值|

|:-:|:-:|:-:|

|[1 3 -1] -3 5 3 6 7[1 3 -1] -3 5 3 6 7|−1−1|33|

| 1 [3 -1 -3] 5 3 6 7 1 [3 -1 -3] 5 3 6 7|−3−3|33|

| 1 3 [-1 -3 5] 3 6 7 1 3 [-1 -3 5] 3 6 7|−3−3|55|

| 1 3 -1 [-3 5 3] 6 7 1 3 -1 [-3 5 3] 6 7|−3−3|55|

| 1 3 -1 -3 [5 3 6] 7 1 3 -1 -3 [5 3 6] 7|33|66|

| 1 3 -1 -3 5 [3 6 7] 1 3 -1 -3 5 [3 6 7]|33|77|

你的任务是找出窗体在各个位置时的最大值和最小值。

输入格式

第 1 行:两个整数 NK

第 2 行:N 个整数,表示数组的 N 个元素(≤2×10^6);

输出格式

第一行为滑动窗口从左向右移动到每个位置时的最小值,每个数之间用一个空格分开;

第二行为滑动窗口从左向右移动到每个位置时的最大值,每个数之间用一个空格分开。

思路:

首先考虑只需求最大值的情况,一个很朴素的想法就是n^2的暴力枚举,然后我们手动模拟就可以发现如果存在s[j]>=s[i]&&j>i,那么在s[j]进入窗口后s[i]不可能成为最大值。所以每当数s进入区间,我们就可以把区间内比它小的全部踢掉。我们用smax数组记录维护区间内每个数在原数组内的下标,top记录区间右端,bot记录区间左端,每次新进来一个数前就一直将top左移直到s[max[top]]>s[i],如此一来区间内的数将是单调递减的,s[smax[bot]]便是区间内最大值,新数进入区间后再将左端右移使得区间长不超过m即可。

最小值的情况同理

#include<iostream>
#include<cstdio>
#define maxn 1010000
using namespace std;
int n,m,smin[maxn],smax[maxn],x,ans[maxn],ansh[maxn],top,bot=1,top1,bot1=1,s[maxn];
int main() {
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++) {
        scanf("%d",&x); 
        s[i]=x;     
        if(top!=0)while(s[smin[top]]>=x&&top>=bot)top--;    
      if(top1!=0)while(s[smax[top1]]<=x&&top1>=bot1)top1--;        
        smin[++top]=i; 
        smax[++top1]=i;
      while(i-smin[bot]>=m)bot++;
      while(i-smax[bot1]>=m)bot1++;
//      printf("top:%d %d bot:%d %d\n",top,s[smin[top]],bot,s[smin[bot]]);
//            printf("%d %d\n",smax[top],smax[bot]);
       ans[i]=smin[bot];
       ansh[i]=smax[bot1];
    }
    for(int i=m;i<=n;i++)printf("%d ",s[ans[i]]);
    puts("");
    for(int i=m;i<=n;i++)printf("%d ",s[ansh[i]]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值