剑指Offer_#59-II_队列的最大值

剑指Offer_#59-II_队列的最大值

Contents

题目

请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value、push_back 和 pop_front 的均摊时间复杂度都是O(1)。
若队列为空,pop_front 和 max_value 需要返回 -1
示例 1:

输入: 
["MaxQueue","push_back","push_back","max_value","pop_front","max_value"]
[[],[1],[2],[],[],[]]
输出: [null,null,null,2,1,2]

示例 2:

输入: 
["MaxQueue","pop_front","max_value"]
[[],[],[]]
输出: [null,-1,-1]

限制:
1 <= push_back,pop_front,max_value的总操作数 <= 10000
1 <= value <= 10^5

思路分析

这一题跟剑指Offer_#59-I_滑动窗口的最大值剑指Offer_#30_包含min函数的栈都有共通之处,可以说是这两题的一个结合。
#30题中,我们使用一个辅助栈来保存每种状态下的最小值。与30题不同的是,这里是实现队列结构,所以不能用栈作为辅助变量。可以借鉴#59题中的双端队列结构来实现功能,即双端队列作为辅助变量,保存每种状态下的最大值。在操作原始数据队列的同时,同步操作辅助双端队列。使得无论什么时候,双端队列的第一个元素就是原始数据队列的最大值。
详见如下图解,来自评论区题解


解答

class MaxQueue {
    Deque<Integer> maxDeque;
    Queue<Integer> queue;
    
    public MaxQueue() {
        queue = new LinkedList<>();
        maxDeque = new LinkedList<>();
    }
    
    public int max_value() {
        if(!maxDeque.isEmpty() && !queue.isEmpty())
            return maxDeque.peekFirst();
        else
            return -1;
    }
    
    public void push_back(int value) {
        queue.offer(value);
        while(!maxDeque.isEmpty() && value > maxDeque.peekLast())
            maxDeque.removeLast();
        maxDeque.addLast(value);
    }
    
    public int pop_front() {
    //ERROR:Integer作为包装类对象,不能直接用==比较,必须用equals()方法比较,见《Core Java》P193
        if(!maxDeque.isEmpty() && maxDeque.peekFirst().equals(queue.peek()))
            maxDeque.removeFirst();
        if(!queue.isEmpty())
            return queue.poll();
        else 
            return -1;
    }
}

复杂度分析

时间复杂度:max_value、push_back 和 pop_front 的复杂度都是O(1)
空间复杂度:O(n),需要借助一个辅助的双端队列

原文地址:https://www.cnblogs.com/Howfars/p/13386757.html