剑指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),需要借助一个辅助的双端队列