一、题目描述
请定义一个队列并实现函数 max_value 得到队列里的最大值,
要求函数max_value、push_back 和 pop_front 的时间复杂度都是O(1)。
若队列为空,pop_front 和 max_value 需要返回 -1
输入:
["MaxQueue","push_back","push_back","max_value","pop_front","max_value"]
[[],[1],[2],[],[],[]]
输出: [null,null,null,2,1,2]
二、题解
方法一:数组模拟队列
思路
head,rear
维护一个窗口。max_value()
:当数组 queue 不空,max 自然会被赋值为大于 1 的数,所以在 isEmpty() 中无需判断。pop_front()
:- 当数组为空,返回 -1。
- 当数组非空,且队头元素
queue[front] == max
时,“弹出” 之前需要对 max 重新寻找最大值。
class MaxQueue {
private int[] queue;
private int head;
private int rear;
private int max;
public MaxQueue() {
queue = new int[10006];
head = 0;
rear = 0;
max = -1;
}
private boolean isEmpty() {
return head == rear;
}
public int max_value() {
return max;
}
public void push_back(int value) {
queue[rear++] = value;
if (value > max)
max = value;
}
public int pop_front() {
if (isEmpty()) return -1;
//如果队头元素和max相等,那么需要对max的值作出改变:
if (queue[head] == max) {
max = -1;
for (int i = head + 1; i < rear; i++) {
if (queue[i] > max)
max = queue[i];
}
}
return queue[head++];
}
}
复杂度分析
方法二:双端队列
保证 sort_que 内部的元素是单调递减的,每次添加元素的时候,sort_que 需要对队尾元素进行判断,如果队尾元素比即将加入队列的 value 要小,那么我们认为队尾的元素是无用的,因为我们要在 max_value 返回最大值。
- 当队列为空,返回 -1。
- 当队列非空,且队头元素
queue.poll() == sort_que.peek()
时,则直接把 sort_que 的队头元素(最大值)弹出。
class MaxQueue {
ArrayDeque<Integer> queue;
ArrayDeque<Integer> sort_que;
public MaxQueue() {
queue = new ArrayDeque<>();
sort_que = new ArrayDeque<>();
}
public int max_value() {
return queue.isEmpty() ? -1 : sort_que.peek();
}
public void push_back(int value) {
queue.add(value);
// 让队列的元素单调递减
while (!sort_que.isEmpty() && value > sort_que.peekLast()) {
sort_que.pollLast();
}
sort_que.add(value);
}
public int pop_front() {
if (queue.isEmpty())
return -1;
int front = queue.poll();
if (front == sort_que.peek()) { //只弹出一个元素
sort_que.poll();
}
return front;
}
}
复杂度分析
- 时间复杂度: ;总的来看,每个元素在队列中,最多不过进入 add 一次和 poll 出队列一次,因此维护队列的最大代价不过是 O(2n)(每个元素都进入一次,再出来一次),而这 O(2n) 是在 n 个循环里面完成的,那么一次操作的时间复杂度为 O(2) = O(1)
- 空间复杂度: ,