滑动窗口思想 && 滑动窗口求最大最小值 洛谷1886

本文详细介绍了滑动窗口算法在求解序列中连续子序列最大值或最小值问题的应用。通过双端队列实现,该算法能高效地处理窗口大小为k的序列问题,适用于动态数据流处理和信号分析等场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

滑动窗口:
一个n个数的序列,要求所有的连续k个数的最大值 或者 最小值,都可以用这种方法实现。

以求最大值为例(最小值反着来就可以了)
窗口大小为k,遍历数组,每次a[i]和队列尾部的元素比较,清空小于a[i]的所有元素,小于的话直接加入。
这样维护是因为窗口不断向后滑动,前面的小于a[i]的一定不会成为后面窗口的最大值,而后面小于它的 等待 大于窗口值时 队头(最大元素)出队,有可能成为最大值。

题目链接
思路:双端队列实现。


#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int AX = 2e6+66;
LL a[AX];
LL deq_MAX[AX];
LL deq_MIN[AX];
//deque<int>deq;

int main(){
    int n , k ;
    ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n >> k ;
    for( int i = 1 ; i <= n ; i++ ){
        cin >> a[i];
    }
    int h1 = 1 , t1 = 0 ;
    int h2 = 1 , t2 = 0 ;
    std::vector<int> v_max;
    std::vector<int> v_min;
    for( int i = 1 ; i <= n ; i ++ ){
        while( h1 <= t1 && a[i] >= a[deq_MAX[t1]] ) t1 -- ;
        deq_MAX[++t1] = i ;

        while( h2 <= t2 && a[i] <= a[deq_MIN[t2]] ) t2 -- ;
        deq_MIN[++t2] = i ;

        if( i >= k ){
            v_max.push_back(a[deq_MAX[h1]]);
            v_min.push_back(a[deq_MIN[h2]]);    

            while( h1 <= t1 && i - k + 1 >= deq_MAX[h1] ) h1 ++;
            while( h2 <= t2 && i - k + 1 >= deq_MIN[h2] ) h2 ++;
        }
    }
    for( int i = 0 ; i < v_min.size() ; i++ ){
        cout << v_min[i] << ' ';
    }cout << endl;
    for( int i = 0 ; i < v_max.size() ; i++ ){
        cout << v_max[i] << ' ';
    }cout << endl;
    return 0 ;
}   
### 问题分析 用户提供的 C 语言代码试图实现滑动窗口最大值和最小值的计算,但存在多个错误,导致程序无法正确运行。以下是对代码中错误的详细分析和修正建议。 --- ### 错误一:数组索引越界 在输入循环中,`for(int i=0;i<n-1;i++)` 导致只读取了 `n-1` 个元素,而数组 `a` 的大小是 `n`,这会导致最后一个元素未被初始化,后续操作可能出现不可预测的行为。 **修正方法:** ```c for(int i=0; i < n; i++) { scanf("%d", &a[i]); } ``` --- ### 错误二:滑动窗口逻辑错误 在计算最大值和最小值的双重循环中: ```c for(int i=0; i < n; i++) { for(int j=i; j < k; j++) { if(a[j+1] > a[j]) b[i] = a[j+1]; if(a[j+1] < a[j]) c[i] = a[j+1]; } } ``` 这段代码的问题在于: 1. 内层循环 `j` 从 `i` 开始,但 `j+1` 可能超出数组边界。 2. 没有正确维护窗口内的最大值和最小值。 3. `b[i]` 和 `c[i]` 没有初始化,可能导致未定义行为。 4. 窗口滑动逻辑错误,未考虑窗口长度为 `k` 的限制。 --- ### 错误三:未使用单调队列结构 题目要使用 **单调队列** 实现滑动窗口最大值和最小值的计算,但当前代码中没有使用任何队列结构,而是试图用双重循环模拟,效率低下且逻辑错误。 --- ### 正确实现:使用单调队列滑动窗口最大值和最小值 以下是一个基于单调队列的 C 语言实现,使用数组模拟队列,并维护其单调性: ```c #include <stdio.h> #include <stdlib.h> #define MAXN 1000010 int a[MAXN], maxq[MAXN], minq[MAXN]; int n, k; int main() { scanf("%d %d", &n, &k); for(int i = 0; i < n; i++) { scanf("%d", &a[i]); } int maxhead = 0, maxtail = 0; int minhead = 0, mintail = 0; for(int i = 0; i < n; i++) { // 维护最大值队列 while(maxtail > maxhead && a[i] >= a[maxq[maxtail - 1]]) { maxtail--; } maxq[maxtail++] = i; // 移除窗口外的元素 while(maxq[maxhead] <= i - k) { maxhead++; } // 输出最大值 if(i >= k - 1) { printf("%d ", a[maxq[maxhead]]); } // 维护最小值队列 while(mintail > minhead && a[i] <= a[minq[mintail - 1]]) { mintail--; } minq[mintail++] = i; // 移除窗口外的元素 while(minq[minhead] <= i - k) { minhead++; } // 输出最小值 if(i >= k - 1) { printf("%d ", a[minq[minhead]]); } } printf("\n"); return 0; } ``` --- ### 优化说明 1. **单调性维护**:每次插入新元素时,确保队列保持单调递减(最大值)或单调递增(最小值)。 2. **窗口滑动**:通过比较索引值判断队列头部是否超出当前窗口范围,若超出则弹出。 3. **输出时机**:只有当窗口已完全形成(即 `i >= k - 1`)时才输出当前窗口的最大值和最小值。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值