这里是题目描述:剑指Offer-面试题59-II:队列的最大值
本题和与它同属于一个大题的剑指Offer-面试题59-I:滑动窗口的最大值都可以用双端队列来存储当前的最大值以及接下来可能成为最大值的元素,来优化时间开销
借助双端队列的解法
本题要求max_value
、push_back
和 pop_front
的均摊时间复杂度都是O(1)。而其中的主要难点就在于让任何状态下的max_value
时间复杂度为O(1)。我们要考虑的是,如何用O(1) 的时间复杂度返回队列中的最大值,同时保证如果最大值出队列,最大值状态发生变化后,依然可以用 O(1) 的时间复杂度找到新的最大值
我们除了需要使用一个单向队列存储进队、出队的元素外,还需建立一个双端队列,借助它存储当前状态下的最大值和可能成为后续状态最大值的值,其中当前最大值位于队头,保证 O(1) 的时间开销可以找到最大值。当有新元素进队列,将它与双端队列队尾元素比较,若队尾元素较小,则证明它不再机会成为某一状态下的最大元素,因为它无论如何会比当前新进队列的元素先出队列,则让队尾元素出队,新元素继续和队尾比较,直到它小于等于队尾元素或双端队列为空,则让它从队尾进入双端队列;当有元素出队列,当出队列元素和双端队列队头值相等时,双端队列队头出队列,新的双端队列队头就是新状态下的最大值
题解代码:
class MaxQueue {
Queue<Integer> queue; //存储队列元素
Deque<Integer> maxValueDeque; //存储当前队列中的最大值和可能的后续最大值
public MaxQueue() {
queue=new LinkedList<>();
maxValueDeque=new LinkedList<>();
}
public int max_value() {
if(queue.size()==0)
{
return -1;
}
return maxValueDeque.getFirst();
}
public void push_back(int value) {
queue.offer(value);
enDeque(maxValueDeque,value);
}
public int pop_front() {
if(queue.size()==0)
{
return -1;
}
int popValue=queue.remove();
if(popValue==maxValueDeque.getFirst())
{
maxValueDeque.removeFirst();
}
return popValue;
}
public void enDeque(Deque<Integer> deque,int value)
{
while(deque.size()>0)
{
if(deque.getLast()<value)
{
deque.removeLast();
}
else
{
break;
}
}
deque.offerLast(value);
}
}