zoukankan      html  css  js  c++  java
  • poj 2823 Sliding Window 单调队列

    poj 2823 Sliding Window
    //poj 2823  Sliding Window
    
    //单调队列
    
    //以下是复制别人的思路的,自己写的代码过不了,这代码也是模仿别人的
    
    //这题还可以用单调队列进行求解。开两个队列,一个维护最大值,
    //一个维护最小值。下面叙述最大队列,最小队列的方法类似。 
    
    //最大队列保证队列中各个元素大小单调递减(注意,不是单调不上升),
    //同时每个元素的下标单调递增。这样便保证队首元素最大,而且更新的
    //时候队首永远是当前最大。因此,这个队列需要在两头都可以进行删除,
    //在队尾插入。
    
    //维护方法:在每次插入的时候,先判断队尾元素,如果不比待插入元素
    //大就删除,不断删除队尾直到队尾元素大于待插入元素或者队空。删除
    //的时候,判断队首,如果队首元素下标小于当前段左边界就删除,不断
    //删除队首直到队首元素下标大于等于当前段左边界(注意:这时队列肯
    //定不为空),队首元素就是当前段的最优解。
    
    
    
    #include <stdio.h>
    #include <string.h>
    
    #define N 1000005
    
    int input()
    {
        char ch;
        int sign = 1, num = 0;
        while(ch = getchar(), ch == '\n' || ch == ' ');
    
        if(ch == EOF)
            return EOF;
    
        if(ch == '-')
        {
            sign = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            num = num * 10 + ch - '0';
            ch = getchar();
        }
        return sign * num;
    }
    
    int arr[N], mn[N], mx[N], time[N], ans[N];
    int len, k;
    
    void getMin()
    {
        int head = 1, tail = 0;
        for(int i = 1; i <= len; ++i)
        {       //删除队尾比要插入的数大的数
            while(head <= tail && mn[tail] >= arr[i])
                tail--;
            mn[++tail] = arr[i];    //把要插入的数插入到队尾,因此
            time[tail] = i;         //队列后面的数肯定比前面的数晚过期
            if(i >= k)
            {
                while(time[head] <= i - k)//注意:这里要等,eg:当i=k+1时
                    head++;               //第一个就过期了
                ans[i-k] = mn[head];
            }
        }
    }
    
    void getMax()
    {
        int head = 1, tail = 0;
        for(int i = 1; i <= len; ++i)
        {
            while(head <= tail && mx[tail] <= arr[i])
                tail--;
            mx[++tail] = arr[i];
            time[tail] = i;
            if(i >= k)
            {
                while(time[head] <= i - k)
                    head++;
                ans[i-k] = mx[head];
            }
        }
    }
    
    void print()
    {
        int end = len-k;    //总的有 1+end 组 宽度为 k 的数
        for(int i = 0; i <= end; ++i)
        {
            printf("%d", ans[i]);
            if(i != end)
                putchar(' ');
        }
        puts("");
    }
    
    int main()
    {
        while(scanf("%d%d", &len, &k) != EOF)
        {
            for(int i = 1; i <= len; ++i)
                arr[i] = input();
            getMin();
            print();
            getMax();
            print();
        }
        return 0;
    }
  • 相关阅读:
    我的浏览器收藏夹分类
    我的浏览器收藏夹分类
    Java实现 LeetCode 318 最大单词长度乘积
    Java实现 LeetCode 318 最大单词长度乘积
    Java实现 LeetCode 318 最大单词长度乘积
    Java实现 LeetCode 316 去除重复字母
    Java实现 LeetCode 316 去除重复字母
    Java实现 LeetCode 316 去除重复字母
    Java实现 LeetCode 315 计算右侧小于当前元素的个数
    Java实现 LeetCode 315 计算右侧小于当前元素的个数
  • 原文地址:https://www.cnblogs.com/gabo/p/2512158.html
Copyright © 2011-2022 走看看