【每日一题】3月30日滑动窗口

滑动窗口

https://ac.nowcoder.com/acm/problem/50528

题目描述

给一个长度为N的数组,一个长为K的滑动窗体从最左端移至最右端,你只能看到窗口中的K个数,每次窗体向右移动一位,你的任务是找出窗体在各个位置时的最大值和最小值。

解题思路

单调队列的经典题目,正如邓老师说的那样,每次区间滑动一个单位,区间内元素从图片说明
变为了图片说明 可以看出,变化的部分,只有a[l]和a[r+1],完全没必要把中间部分去遍历很多遍。
这时候就请来了强大的单调队列大大,开辟一个队列,让里面保存的都是可能是答案的下标,并且当前位置的答案下标保存在对头中。
具体的实现过程注释的比较详细,当前元素如果要入队,之前的对头下标如果和自己差距大于m,说明以前的下标不合法了,队头出队。
拿求最小值来说,如果队尾元素大于等于当前a[i],a[i]入队后,最小值不可能是当前队尾了,队尾元素出队。反复循环直到队尾元素小于a[i]。

Code

#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
typedef long long ll;

inline int read() {
    int s = 0, w = 1; char ch = getchar();
    while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); }
    while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return s * w;
}

const int N = 1e6 + 7;
int a[N], que[N];

int main() {
    int n = read(), m = read();
    for (int i = 1; i <= n; ++i)
        a[i] = read();
    int l = 0, r = 0; //单调队列队头和队尾
    que[r++] = 1;
    if (m == 1)    printf("%d ", a[1]); //后面从2开始特判下m
    for (int i = 2; i <= n; ++i) {
        //队中存在元素,并且之前的最小元素下标已经不在当前m范围内 出队
        if (r > l && i - que[l] >= m)    ++l;
        //  当前队尾值大于等于a[i] a[i]入队后,最小值一定不会是队尾了,队尾出队
        while (r > l && a[que[r - 1]] >= a[i])    --r;

        que[r++] = i;
        if (i >= m)
            printf("%d ", a[que[l]]); //队头中保存的就是最小值下标位置
    }
    puts("");
    // 最大值类似
    l = r = 0;
    que[r++] = 1;
    if (m == 1)    printf("%d ", a[1]);
    for (int i = 2; i <= n; ++i) {
        //队中存在元素,并且之前的最大元素下标已经不在当前m范围内 出队
        if (r > l && i - que[l] >= m)    ++l;
        //  当前队尾值小于等于a[i] a[i]入队后,最大值一定不会是队尾了,队尾出队
        while (r > l && a[que[r - 1]] <= a[i])    --r;

        que[r++] = i;
        if (i >= m)
            printf("%d ", a[que[l]]); //队头中保存的就是最大值下标位置
    }
    puts("");
    return  0;
}
每日一题 文章被收录于专栏

每日一题

全部评论

相关推荐

2025-12-28 20:47
已编辑
北京工商大学 Java
程序员牛肉:我靠你这个实习经历其实最需要担心的点是你做的太多了,可能会被面试官怀疑是你伪造的。 交易状态机是你做的,支付多渠道是你做的,对账是你做的,结算还是你做的,重复支付也是你做的,整个服务的异常处理也是你做的。 其实你这个反而问题很大的,你想想站在面试官的角度,他是真的会相信你的能力很强,还是相信这份实习你伪造了大部分?我相信你真的做了这么多,但是删一些,废话删一删。你这个做的太多了反而真实性不可信。 后面再补一个项目,在github上找一个高star的项目学一学然后写到自己简历上。我觉得你能力肯定没问题。28届能做到这个份上很厉害,但是在求职市场中,你不是在跟28届的同学比,把你这个简历放到27届其实也就一般水平。 所以后续要想一想看看能不能给自己简历上搞点亮点,比如开源贡献呢?比如博客呢?
实习要如何选择和准备?
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务