Description

An array of size n ≤ 106 is given to you. There is a sliding window of
size k which is moving from the very left of the array to the very
right. You can only see the k numbers in the window. Each time the
sliding window moves rightwards by one position. Following is an
example: The array is [1 3 -1 -3 5 3 6 7],and k is 3. Window
position Minimum value Maximum value [1 3 -1] -3 5 3 6 7 -1 3
1 [3 -1 -3] 5 3 6 7 -3 3 1 3 [-1 -3 5] 3 6 7 -3 5 1 3
-1 [-3 5 3] 6 7 -3 5 1 3 -1 -3 [5 3 6] 7 3 6 1 3 -1 -3 5 [3 6 7] 3 7 Your task is to determine the maximum and minimum
values in the sliding window at each position.

Input

The input consists of two lines. The first line contains two integers
n and k which are the lengths of the array and the sliding window.
There are n integers in the second line.

Output

There are two lines in the output. The first line gives the minimum
values in the window at each position,from left to right,
respectively. The second line gives the maximum values.

Sample Input

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

Sample Output

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

思路

这是著名的滑动窗口问题,就是单调队列的基本问题。。这道题主要说一下单调队列解法

单调队列的一般问题是这么描述的:

给定一个长度为N的整数数列a(i),i=0,1,…,N-1和窗长度k.

要求:

f(i) = max{a(i-k+1),a(i-k+2),...,a(i)},i = 0,N-1

问题的另一种描述就是用一个长度为k的窗在整数数列上移动,求窗里面所包含的数的最大值。

解法一:

很直观的一种解法,那就是从数列的开头,将窗放上去,然后找到这最开始的k个数的最大值,然后窗最后移一个单元,继续找到k个数中的最大值。

这种方法每求一个f(i),都要进行k-1次的比较,复杂度为O(N*k)。

那么有没有更快一点的算法呢?

解法二:

我们知道,上一种算法有一个地方是重复比较了,就是在找当前的f(i)的时候,i的前面k-1个数其它在算f(i-1)的时候我们就比较过了。那么我们能不能保存上一次的结果呢?当然主要是i的前k-1个数中的最大值了。答案是可以,这就要用到单调递减队列。

单调递减队列是这么一个队列,它的头元素一直是队列当中的最大值,而且队列中的值是按照递减的顺序排列的。我们可以从队列的末尾插入一个元素,可以从队列的两端删除元素。

  1. 首先看插入元素:为了保证队列的递减性,我们在插入元素v的时候,要将队尾的元素和v比较,如果队尾的元素不大于v,则删除队尾的元素,然后继续将新的队尾的元素与v比较,直到队尾的元素大于v,这个时候我们才将v插入到队尾。

  2. 队尾的删除刚刚已经说了,那么队首的元素什么时候删除呢?由于我们只需要保存i的前k-1个元素中的最大值,所以当队首的元素的索引或下标小于 i-k+1的时候,就说明队首的元素对于求f(i)已经没有意义了,因为它已经不在窗里面了。所以当index[队首元素]<i-k+1时,将队首
    元素删除。

从上面的介绍当中,我们知道,单调队列与队列唯一的不同就在于它不仅要保存元素的值,而且要保存元素的索引(当然在实际应用中我们可以只需要保存索引,而通过索引间接找到当前索引的值)。

为了让读者更明白一点,我举个简单的例子。

假设数列为:8,7,12,5,16,9,17,2,4,6.N=10,k=3.

那么我们构造一个长度为3的单调递减队列:

首先,那8和它的索引0放入队列中,我们用(8,0)表示,每一步插入元素时队列中的元素如下:

0:插入8,队列为:(8,0)

1:插入7,队列为:(8,0),(7,1)

2:插入12,队列为:(12,2)

3:插入5,队列为:(12,2),(5,3)

4:插入16,队列为:(16,4)

5:插入9,队列为:(16,4),(9,5)

。。。。依此类推

那么f(i)就是第i步时队列当中的首元素:8,8,12,12,16,16,。。。

一般来说,dequeSTL总的双端队列容器,用deque可以很方便的实现单调队列

代码

单调队列:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <stdlib.h>
#include <string>
#include <map>
#include <iostream>
#include <sstream>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>
#include <list>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt << 1
#define rson m + 1,r,rt << 1 | 1
#define rson m + 1,rt << 1 | 1
#define inf 0x3f3f3f3f
typedef long long ll;
typedef pair<int,int> pir;
const int N = 1e6 + 10;
deque<pir> q1; //维护最大值
deque<pir> q2; //维护最小值
int x,MIN[N],MAX[N];
int main()
{
    //freopen("in.txt","r",stdin);
    int n,k;
    scanf("%d%d",&n,&k);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d",&x);
        while (!q1.empty() && q1.back().first >= x) //队列递增
            q1.pop_back();
        q1.push_back(make_pair(x,i));
        if (i >= k)
        {
            while (!q1.empty() && q1.front().second <= i - k) //>的时候出去
                q1.pop_front();
            MIN[i] = q1.front().first;
        }
        while (!q2.empty() && q2.back().first <= x) //队列递减
            q2.pop_back();
        q2.push_back(make_pair(x,i));
        if (i >= k)
        {
            while (!q2.empty() && q2.front().second <= i - k)
                q2.pop_front();
            MAX[i] = q2.front().first;
        }
    }
    for (int i = k; i <= n; i++)
        printf("%d ",MIN[i]);
    puts("");
    for (int i = k; i <= n; i++)
        printf("%d ",MAX[i]);
    puts("");

    return 0;
}

set做法(poj过不了,scu可过)

#include <cstdio>
#include <cstring>
#include <cctype>
#include <stdlib.h>
#include <string>
#include <map>
#include <iostream>
#include <sstream>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>
#include <list>
using namespace std;
#define mem(a,rt << 1 | 1
#define inf 0x3f3f3f3f
typedef long long ll;
const int N = 1e6 + 10;
multiset<int> s;
int a[N],ans1[N],ans2[N];
int main()
{
   // freopen("in.txt",k;
    while (~scanf("%d%d",&k))
    {
        s.clear();
        for (int i = 1; i <= n; i++)
        {
            scanf("%d",&a[i]);
            if (i <= k)
                s.insert(a[i]);
        }
        for (int i = 1; i <= n - k + 1; i++)
        {
            int j = i + k - 1;
            ans1[i] = *s.begin();
            ans2[i] = *s.rbegin();
            s.erase(s.find(a[i]));
            s.insert(a[j + 1]);
        }
        for (int i = 1; i <= n - k + 1; i++)
        {
            printf("%d ",ans1[i]);
        }
        printf("\n");
        for (int i = 1; i <= n - k + 1; i++)
        {
            printf("%d ",ans2[i]);
        }
        printf("\n");
    }
    return 0;
}

线段树:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <stdlib.h>
#include <string>
#include <map>
#include <iostream>
#include <sstream>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>
#include <list>
using namespace std;
#define mem(a,rt << 1 | 1
#define inf 0x3f3f3f3f
typedef long long ll;
const int N = 1e6 + 10;
int ans1[N],ans2[N];
int MAX[N << 2],MIN[N << 2];
void pushup(int rt)
{
    MAX[rt] = max(MAX[rt << 1],MAX[rt << 1 | 1]);
    MIN[rt] = min(MIN[rt << 1],MIN[rt << 1 | 1]);
}
void build(int l,int r,int rt)
{
    if (l == r)
    {
        scanf("%d",&MAX[rt]);
        MIN[rt] = MAX[rt];
        return;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    pushup(rt);
}
void update(int p,int add,int l,int rt)
{
    if (l == r)
    {
        MAX[rt] = add;
        MIN[rt] = add;
        return;
    }
    int m = (l + r) >> 1;
    if (p <= m)
        update(p,add,lson);
    else
        update(p,rson);
    pushup(rt);
}
int query_max(int L,int R,int rt)
{
    if (L <= l && r <= R)
        return MAX[rt];
    int m = (l + r) >> 1;
    int ans = -inf;
    if (L <= m)
        ans = max(ans,query_max(L,R,lson));
    if (R > m)
        ans = max(ans,rson));
    return ans;
}
int query_min(int L,int rt)
{
    if (L <= l && r <= R)
        return MIN[rt];
    int m = (l + r) >> 1;
    int ans = inf;
    if (L <= m)
        ans = min(ans,query_min(L,lson));
    if (R > m)
        ans = min(ans,rson));
    return ans;
}
int main()
{

    //freopen("in.txt",&k))
    {
        build(1,n,1);
        for (int i = 1; i <= n - k + 1; i++)
        {
            int j = i + k - 1;
            ans2[i] = query_max(i,j,1,1);
            ans1[i] = query_min(i,1);
        }
        for (int i = 1; i <= n - k + 1; i++)
            printf("%d ",ans1[i]);
        printf("\n");
        for (int i = 1; i <= n - k + 1; i++)
            printf("%d ",ans2[i]);
        printf("\n");
    }
    return 0;
}

POJ2823 Sliding Window(单调队列,线段树,set,deque)的更多相关文章

  1. 使用最新的Flurry SDK和ios4重新启动应用程序

    我真的希望这对我来说只是一个愚蠢的错误.我很高兴使用Flurry但这样的事情会导致我的应用被拒绝.解决方法我写了关于这个的Flurry,他们很快回到我身边,他们会调查这个.大约一个星期后,他们回信并表示他们已经在v2.6中修复了它,现在可用了.我似乎无法重现这个问题.不是说我很棒或者什么,但我还是单枪匹马地解决了这个问题.

  2. 如何在Xcode 4.1中调试OpenCL内核?

    我有一些OpenCL内核没有做他们应该做的事情,我很想在Xcode中调试它们.这可能吗?当我在我的内核中使用printf()时,OpenCL编译器总是给我一大堆错误.解决方法将格式字符串转换为constchar*似乎可以解决此问题.这适用于Lion:这有上述错误:

  3. 六种语言实现输出乘法口诀表

    六种语言实现输出乘法口诀表Objective-cC语言javaJavaScriptSwiftPython可以看出不同语言又不同的写法,从上到下,代码越来越少,越来越简洁,也能够看出这些语言的各自的一些特点。

  4. Swift---一门智能型的编程语言

    Swift是苹果公司于2014年推出的一门全新的编程语言,目前已进化至第三版。简单地说,Swift是一门智能型的语言,为程序员解决了在使用很多其他的编程语言的过程中所经常遇到的问题。下面,我就拿Swift和C语言进行对比,用几个例子为大家展示Swift为何是“智能”的。从变量类型的自动推断中也可以看出,Swift具备一定的“智能”。那么,Swift是否受到了大家的欢迎呢?考虑到Swift也才推出来两年,这个排行算是不错的了。

  5. android – 使用FFmpeg检索专辑封面

    我正在开发一个依赖于FFmpeg来检索音频元数据的Android应用程序.我知道可以使用FFMpeg以编程方式检索专辑封面.但是,一旦您解码了艺术,如何生成图像文件以便在应用程序中使用?

  6. Java数据结构之线段树的原理与实现

    线段树是一种二叉搜索树,是用来维护区间信息的数据结构。本文将利用示例详细讲讲Java数据结构中线段树的原理与实现,需要的可以参考一下

  7. 深入剖析PHP中printf()函数格式化使用

    下面小编就为大家带来一篇深入剖析PHP中printf()函数格式化使用。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  8. 深入理解php printf() 输出格式化的字符串

    下面小编就为大家带来一篇深入理解php printf() 输出格式化的字符串。小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  9. PHP中的输出echo、print、printf、sprintf、print_r和var_dump的示例代码

    这篇文章主要介绍了PHP中的输出echo、print、printf、sprintf、print_r和var_dump的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  10. Java数据结构之线段树中的懒操作详解

    对于线段树,若要求对区间中的所有点都进行更新,可以引入懒操作。懒操作包括区间更新和区间查询操作。本文将通过一个示例和大家详细聊聊线段树中的懒操作,需要的可以参考一下

随机推荐

  1. static – 在页面之间共享数据的最佳实践

    我想知道在UWP的页面之间发送像’selectedItem’等变量的最佳做法是什么?创建一个每个页面都知道的静态全局变量类是一个好主意吗?

  2. .net – 为Windows窗体控件提供百分比宽度/高度

    WindowsForm开发的新手,但在Web开发方面经验丰富.有没有办法为Windows窗体控件指定百分比宽度/高度,以便在用户调整窗口大小时扩展/缩小?当窗口调整大小时,可以编写代码来改变控件的宽度/高度,但我希望有更好的方法,比如在HTML/CSS中.在那儿?

  3. 使用Windows Azure查询表存储数据

    我需要使用特定帐户吗?>将应用程序部署到Azure服务后,如何查询数据?GoogleAppEngine有一个数据查看器/查询工具,Azure有类似的东西吗?>您可以看到的sqlExpressintance仅在开发结构中,并且一旦您表示没有等效,所以请小心使用它.>您可以尝试使用Linqpad查询表格.看看JamieThomson的thispost.

  4. windows – SetupDiGetClassDevs是否与文档中的设备实例ID一起使用?

    有没有更好的方法可以使用DBT_DEVICEARRIVAL事件中的数据获取设备的更多信息?您似乎必须指定DIGCF_ALLCLASSES标志以查找与给定设备实例ID匹配的所有类,或者指定ClassGuid并使用DIGCF_DEFAULT标志.这对我有用:带输出:

  5. Windows Live ID是OpenID提供商吗?

    不,WindowsLiveID不是OpenID提供商.他们使用专有协议.自从他们的“测试版”期结束以来,他们从未宣布计划继续它.

  6. 如果我在代码中进行了更改,是否需要重新安装Windows服务?

    我写了一个Windows服务并安装它.现在我对代码进行了一些更改并重新构建了解决方案.我还应该重新安装服务吗?不,只需停止它,替换文件,然后重新启动它.

  7. 带有双引号的字符串回显使用Windows批处理输出文件

    我正在尝试使用Windows批处理文件重写配置文件.我循环遍历文件的行并查找我想要用指定的新行替换的行.我有一个’函数’将行写入文件问题是%Text%是一个嵌入双引号的字符串.然后失败了.可能还有其他角色也会导致失败.如何才能使用配置文件中的所有文本?尝试将所有“在文本中替换为^”.^是转义字符,因此“将被视为常规字符你可以尝试以下方法:其他可能导致错误的字符是:

  8. .net – 将控制台应用程序转换为服务?

    我正在寻找不同的优势/劣势,将我们长期使用的控制台应用程序转换为Windows服务.我们为ActiveMQ使用了一个叫做java服务包装器的东西,我相信人们告诉我你可以用它包装任何东西.这并不是说你应该用它包装任何东西;我们遇到了这个问题.控制台应用程序是一个.NET控制台应用程序,默认情况下会将大量信息记录到控制台,尽管这是可配置的.任何推荐?我们应该在VisualStudio中将其重建为服务吗?我使用“-install”/“-uninstall”开关执行此操作.例如,seehere.

  9. windows – 捕获外部程序的STDOUT和STDERR *同时*它正在执行(Ruby)

    哦,我在Windows上:-(实际上,它比我想象的要简单,这看起来很完美:…是的,它适用于Windows!

  10. windows – 当我试图批量打印变量时,为什么我得到“Echo is on”

    我想要执行一个简单的批处理文件脚本:当我在XP中运行时,它给了我预期的输出,但是当我在Vista或Windows7中运行它时,我在尝试打印值时得到“EchoisOn”.以下是程序的输出:摆脱集合表达式中的空格.等号(=)的两侧可以并且应该没有空格BTW:我通常在@echo关闭的情况下启动所有批处理文件,并以@echo结束它们,所以我可以避免将代码与批处理文件的输出混合.它只是使您的批处理文件输出更好,更清洁.

返回
顶部