洛谷P1886滑动窗口/单调队列

该文章描述了一种算法问题,涉及在一个序列上使用固定大小的窗口向右滑动,每次滑动时计算窗口内的最大值和最小值。给出的Java和C++代码示例实现了这个问题的解决方案,使用双端队列来高效地维护窗口内的最大值和最小值。
摘要由CSDN通过智能技术生成

题目描述

有一个长为 n 的序列 a,以及一个大小为 k 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。

例如:

The array is [1,3,−1,−3,5,3,6,7][1,3,−1,−3,5,3,6,7], and k=3。

输入格式

输入一共有两行,第一行有两个正整数 n,k。 第二行 n 个整数,表示序列 a

输出格式

输出共两行,第一行为每次窗口滑动的最小值
第二行为每次窗口滑动的最大值

输入输出样例

输入 #1复制

8 3
1 3 -1 -3 5 3 6 7

输出 #1复制

-1 -3 -3 -3 3 3
3 3 5 5 6 7

说明/提示

【数据范围】
对于 50%50% 的数据,1≤�≤1051≤n≤105;
对于 100%100% 的数据,1≤�≤�≤1061≤k≤n≤106,��∈[−231,231)ai​∈[−231,231)。

 JAVA代码:


import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        int[] a = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            a[i] = scanner.nextInt();
        }
        Deque<Integer> minQueue = new LinkedList<>();
        Deque<Integer> maxQueue = new LinkedList<>();
        for (int i = 1; i <= n; i++) {
            // Find the minimum value in current window
            // 查找当前窗口内的最小值
            while (!minQueue.isEmpty() && a[minQueue.peekLast()] > a[i]) {
//                peeklast检索但不删除
//                polllast检索并删除
                // 队尾元素不是最小值,从队列中删除
                minQueue.pollLast();//去尾
            }
            minQueue.offerLast(i);// 加入当前元素下标
            if (i >= m) {
                 while (!minQueue.isEmpty() && minQueue.peekFirst() <= i - m) {
                    // 删除不在窗口内的元素下标
                    minQueue.pollFirst();//删头
                }
                System.out.print(a[minQueue.peekFirst()] + " ");
            }
        }
        System.out.println();
// 查找当前窗口内的最大值
        for (int i = 1; i <= n; i++) {
            // Find the maximum value in current window
            while (!maxQueue.isEmpty() && a[maxQueue.peekLast()] < a[i]) {

                maxQueue.pollLast();
            }
            maxQueue.offerLast(i);
            if (i >= m) {
                while (!maxQueue.isEmpty() && maxQueue.peekFirst() <= i - m) {
                    maxQueue.pollFirst();
                }
                System.out.print(a[maxQueue.peekFirst()] + " ");
            }
        }
        scanner.close();
    }
}

C++代码:


#include <iostream>
#include <deque>

using namespace std;
const int N = 1000005;
int a[N];
deque<int>q;                   //队列中的数据,实际上是元素在原序列中的位置
int main(){
    int n,m;   scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)    scanf("%d",&a[i]);
    for(int i=1;i<=n;i++){                       //输出最小值
        while(!q.empty() && a[q.back()]>a[i])     q.pop_back();   //去尾
        q.push_back(i);
        if(i>=m){      //每个窗口输出一次
            while(!q.empty() && q.front()<=i-m)    q.pop_front();  //删头
            printf("%d ", a[q.front()]);
        }
    }
    printf("\n");
    while(!q.empty())  q.pop_front();            //清空,下面再用一次
    for(int i=1;i<=n;i++){                       //输出最大值
        while(!q.empty() && a[q.back()]<a[i])  q.pop_back();   //去尾
        q.push_back(i);
        if(i>=m){
            while(!q.empty() && q.front()<=i-m) q.pop_front();  //删头
            printf("%d ", a[q.front()]);
        }
    }
    printf("\n");
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安小生学编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值