POJ ~ 2823 ~ Sliding Window (单调队列 or RMQ or 线段树)

题意:给你n个数字,现在有一个长度为k窗口,每次往右移动一位,问窗口中的最小值和最大值;


思路:滑动窗口最值问题,用单调队列解。也可以用RMQ和线段树过。


坑点:G++可能会超时,C++能过。

单调队列:

//#include<bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int MAXN = 1000005;
int n, k, a[MAXN], Max[MAXN], Min[MAXN];
int deq_Min[MAXN], deq_Max[MAXN], front1, rear1, front2, rear2;
int main()
{
    scanf("%d%d", &n, &k);
    for (int i = 0; i < n; i++) scanf("%d", &a[i]);
    front1 = rear1 = front2 = rear2 = 0;
    for (int i = 0; i < n; i++)
    {
        //最小值
        if (deq_Min[front1] == i-k) front1++;
        while (front1 < rear1 && a[deq_Min[rear1-1]] >= a[i]) rear1--;
        deq_Min[rear1++] = i;
        Min[i] = a[deq_Min[front1]];
        //最大值
        if (deq_Max[front2] == i-k) front2++;
        while (front2 < rear2 && a[deq_Max[rear2-1]] <= a[i]) rear2--;
        deq_Max[rear2++] = i;
        Max[i] = a[deq_Max[front2]];
    }
    for (int i = k-1; i < n; i++) printf("%d ", Min[i]); printf("\n");
    for (int i = k-1; i < n; i++) printf("%d ", Max[i]); printf("\n");
    return 0;
}
/*
8 3
1 3 -1 -3 5 3 6 7
*/


RMQ:

如果直接用RMQ的话会MLE(超内存),因为本题的查询长度恒为k,我们只需要保存 j*2<k  时最大那个j的即可,数组就不必要开那么大了,开成一维,递推到上面所说的 j 的情况停止。

//#include<bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int MAXN = 1000005;
int n, k, j, ST_Max[MAXN], ST_Min[MAXN];
int main()
{
    scanf("%d%d", &n, &k);
    for (int i = 0; i < n; i++)
    {
        int t; scanf("%d", &t);
        ST_Min[i] = ST_Max[i] = t;
    }
    //RMQ
    for (j = 1; j*2 < k; j *= 2)
    {
        for (int i = 0; i+j < n; i++)
        {
            ST_Min[i] = min(ST_Min[i], ST_Min[i+j]);
            ST_Max[i] = max(ST_Max[i], ST_Max[i+j]);
        }
    }
    for (int i = 0; i+k <= n; i++) printf("%d ", min(ST_Min[i], ST_Min[i+k-j])); printf("\n");
    for (int i = 0; i+k <= n; i++) printf("%d ", max(ST_Max[i], ST_Max[i+k-j])); printf("\n");
    return 0;
}
/*
8 3
1 3 -1 -3 5 3 6 7
*/


线段树:

//#include<bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int MAXN = 1000005;
const int MaxNode = MAXN * 4;
const int INF = 1000000005;
int n, k, ans1[MAXN], ans2[MAXN];
struct IntervalTree
{
    int minv[MaxNode], maxv[MaxNode];
    int pos, v;
    int qL, qR, _min, _max;
    void maintain(int o, int L, int R)
    {
        int lc = o*2, rc = o*2+1;
        if (R > L)
        {
            minv[o] = min(minv[lc], minv[rc]);
            maxv[o] = max(maxv[lc], maxv[rc]);
        }
    }

    void update(int o, int L, int R)
    {
        if (L == R)
        {
            minv[o] = maxv[o] = v;
            return ;
        }
        int lc = o*2, rc = o*2+1, M = L + (R-L)/2;
        if (pos <= M) update(lc, L, M);
        if (pos > M) update(rc, M+1, R);
        maintain(o, L, R);
    }

    void query(int o, int L, int R)
    {
        if (qL <= L && R <= qR)
        {
            _min = min(_min, minv[o]);
            _max = max(_max, maxv[o]);
            return ;
        }
        int lc = o*2, rc = o*2+1, M = L + (R-L)/2;
        if (qL <= M) query(lc, L, M);
        if (qR > M) query(rc, M+1, R);
    }
};
IntervalTree tree;
int main()
{
    scanf("%d%d", &n, &k);
    {
        for (int i = 1; i <= n; i++)
        {
            int t; scanf("%d", &t);
            tree.pos = i; tree.v = t;
            tree.update(1, 1, n);
        }
        for (int i = 1; i+k-1 <= n; i++)
        {
            tree.qL = i; tree.qR = i+k-1;
            tree._min = INF; tree._max = -INF;
            tree.query(1, 1, n);
            ans1[i] = tree._min;  ans2[i] = tree._max;
        }
        for (int i = 1; i+k-1 <= n; i++) printf("%d ", ans1[i]); printf("\n");
        for (int i = 1; i+k-1 <= n; i++) printf("%d ", ans2[i]); printf("\n");
    }
    return 0;
}
/*
8 3
1 3 -1 -3 5 3 6 7
*/



超时的set方法(感觉不应该超时的啊):

//#include<bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <set>
using namespace std;
const int MAXN = 1000005;
int n, k, a[MAXN], ans1[MAXN], ans2[MAXN];
multiset<int> s;
int main()
{
    scanf("%d%d", &n, &k);
    {
        for (int i = 0; i < n; i++)
        {
            scanf("%d", &a[i]);
            if (i < k) s.insert(a[i]);
        }
        for (int i = 0; i+k-1 < n; i++)
        {
            ans1[i] = *s.begin(); ans2[i] = *s.rbegin();
            s.erase(a[i]);
            s.insert(a[i+k]);
        }
        for (int i = 0; i+k-1 < n; i++) printf("%d ", ans1[i]); printf("\n");
        for (int i = 0; i+k-1 < n; i++) printf("%d ", ans2[i]); printf("\n");
    }
    return 0;
}
/*
8 3
1 3 -1 -3 5 3 6 7
*/


weixin073智慧旅游平台开发微信小程序+ssm后端毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
python017基于Python贫困生资助管理系统带vue前后端分离毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值