• poj 2823 Sliding Window


          在这里先说一道微软的面试题目———《队列中的最大值》

          让你设计一个队列,是其求里面最大值的时间复杂度尽可能的低,但这个队列除了最大值外,就是一个普通的队列,该怎么进出还是怎么进出,并不是优先队列。

          对于一堆树,我们求其中最大值一般都会直接遍历一次,然后找到最大值,这样的话时间复杂度是O(n),如果在这道题里面用这种方法总的时间复杂度会到O(n^2),考虑到n的大小,这种方法显然是行不通的。有没有更为快速,可能有人想到使用堆,这也是优先队列使用的方法,如果实现的好的话,可以把时间复杂度从O(n)降到O(logn),不过,我这里说的不是这种方法,我要来说一下时间复杂度为O(1)的一种算法。

          在说这个算法之前,我先要讲两个东西———栈里面的最大值和用两个栈实现一个队列。

          我们很容易可以把求栈里面的最大值问题的时间复杂度降到O(1),我们在栈的每一个节点保存两个值Val和Max,一个是原来应该保存的值,另一个是max值,就是当这个节点是栈顶时栈中最大的值,如果新来一个数x,那么添加一个节点val = x, Max = max(stack.top().Max, x),这样的话即使我们执行了多长pop操作也可以在O(1)的时间里求出里面的最大值,如果不明白请看下图。


    比如说这就是一个有7个元素的栈,左边val就是原来的值,右边就是max,比如说当top指针如图所示,5就是栈里面最大的值,如果我们执行一次pop,我们还是可以一次得到栈里面最大的值。

            关于用两个栈实现一个队列,如果将一串数分别入栈和入队列,然后出栈出队列,我们就会发现一个顺序反了,一个没有。如果我们用栈实现队列必须用两个栈,反一次,然后再反一次,不就正好是队列的顺序了吗?

            然后我们姑且就称这个用栈实现的队列叫Queue吧,这样的话还有一个出人对列的问题,还记得出队列的顺序吗?先入的先出,那我们到底应该怎么实现呢? 看看这个Queue里面吧, 里面有个两个栈,我们就叫In和Out栈吧。如下图


        为什么是In和Out,因为,我们入Queue的时候把元素放的In栈里面,出Queue的时候从Out栈里面出,还有在出入Queue的时候适时把In里面的元素放到Out里面,适时到底是什么时候?  就是出Queue的时候Out里面没有元素了,然后把In里面所有元素压的Out栈里面,注意是所有元素,这样才能保证他们出入Queue的顺序正好是一个出入队列的顺序。

             说了这么多,我们在来看看这道题,一个区间每次向后移动一位,然后求里面的最大最小值,这个过程不就是先把最早进入区间的一个数去掉,然后加入一个数,这个不就是一个队列吗??然后让你找队列里面的最大最小值(详情请参考《剑指offer》一书,具体多少页我忘记了)  有了上面两个知识,我们就可以在O(n)的时间复杂度里面解决这个问题了。

             下面是解题代码,不过还是超时了,我想可能是因为多次调用函数的原因,思路是完全正确的,大家可以尝试把那些东西写一起,还有这个题的输入输出数据量极大,不要用cin cout输入输出,不然会超时的。

    备注:这道题貌似可以用动态规划的方法做,不过本弱菜不会,如有读者会希望不吝赐教。

    //poj 2823
    //2013-08-03-10.39
    #include <stdio.h>
    #include <stack>
    #include <algorithm>
    #define maxn 1000006
    using namespace std;
    
    int maxv[maxn];
    int minv[maxn];
    int cnt;
    
    struct node
    {
        int val, maxv, minv;
    };
    stack<node> sin;
    stack<node> sout;
    
    void push(int v)
    {
        if (sin.empty())
        {
            node tmp;
            tmp.val = v;
            tmp.maxv = v;
            tmp.minv = v;
            sin.push(tmp);
        }
        else
        {
            node tmp = sin.top();
            tmp.val = v;
            tmp.maxv = max(tmp.maxv, v);
            tmp.minv = min(tmp.minv, v);
            sin.push(tmp);
        }
    }
    
    void pop()
    {
        if (sout.empty())
        {
            while (!sin.empty())
            {
                node tmp = sin.top();
                sin.pop();
                if (sout.empty())
                {
                    tmp.maxv = tmp.val;
                    tmp.minv = tmp.val;
                    sout.push(tmp);
                }
                else
                {
                    node tmp2 = sout.top();
                    tmp.maxv = max(tmp2.maxv, tmp.val);
                    tmp.minv = min(tmp2.minv, tmp.val);
                    sout.push(tmp);
                }
            }
            sout.pop();
        }
        else
        {
            sout.pop();
        }
    }
    
    void getval()
    {
        if(!sin.empty() && !sout.empty())
        {
            node tin = sin.top(), tout = sout.top();
            minv[cnt] = min(tin.minv, tout.minv);
            maxv[cnt] = max(tin.maxv, tout.maxv);
            cnt++;
        }
        if (sin.empty() && !sout.empty())
        {
            node tout = sout.top();
            minv[cnt] = tout.minv;
            maxv[cnt] = tout.maxv;
            cnt++;
        }
        if (!sin.empty() && sout.empty())
        {
            node tin = sin.top();
            minv[cnt] = tin.minv;
            maxv[cnt] = tin.maxv;
            cnt++;
        }
    }
    
    int main()
    {
        int n, k;
        while (scanf("%d %d", &n, &k) != EOF)
        {
            int tmp;
            cnt = 1;
            while (!sin.empty())
                sin.pop();
            while (!sout.empty())
                sout.pop();
            for (int i = 1; i <= n; i++)
            {
                scanf("%d", &tmp);
                push(tmp);
                if (i == k)
                {
                    getval();
                }
                if (i > k)
                {
                    pop();
                    getval();
                }
            }
            for (int i = 1; i < cnt; i++)
            {
                if (i == 1)
                    printf("%d", minv[i]);
                else
                    printf(" %d", minv[i]);
            }
            puts("");
            for (int i = 1; i < cnt; i++)
            {
                if (i == 1)
                    printf("%d", maxv[i]);
                else
                    printf(" %d", maxv[i]);
            }
            puts("");
        }
        return 0;
    }
    

     

  • 相关阅读:
    Python爬虫学习==>第十二章:使用 Selenium 模拟浏览器抓取淘宝商品美食信息
    Python爬虫学习==>第十一章:分析Ajax请求-抓取今日头条信息
    Python爬虫学习==>第十章:使用Requests+正则表达式爬取猫眼电影
    Python爬虫学习==>第九章:正则表达式基础
    Python爬虫学习==>第八章:Requests库详解
    Python爬虫学习==>第七章:urllib库的基本使用方法
    Python爬虫学习==>第六章:爬虫的基本原理
    Python爬虫学习==>第五章:爬虫常用库的安装
    纵横字谜的答案(Crossword Answers)
    谜题
  • 原文地址:https://www.cnblogs.com/xindoo/p/3595058.html
Copyright © 2020-2023  润新知