1.题目
剑指 Offer 59 - II. 队列的最大值
请定义一个队列并实现函数 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
2.自我思路及实现
未AC
试图通过一个哈希表来存储以压入元素为起点的最大值,但是失败,会覆盖掉已经存储好的最大值
class MaxQueue {
LinkedList<Integer> queue;
Map<Integer, Integer> map;
int max;
int count;
int curIndex;
public MaxQueue() {
this.queue = new LinkedList<>();
this.map = new HashMap<>();
this.max = 0;
this.count = 0;
this.curIndex = 1;
}
public int max_value() {
if(queue.isEmpty())
return -1;
return map.get(curIndex);
}
public void push_back(int value) {
queue.addLast(value);
count++;
for(int i = 1; i <= count; i++)
{
if(value > max)
{
max = value;
map.put(i, max);
}
else
map.put(i, max);
}
}
public int pop_front() {
if(queue.isEmpty())
return -1;
curIndex ++;
return queue.removeFirst();
}
}
3.总结思路及实现
单调的双端队列
当一个元素入队列时,它前面所有比它小的元素对答案就没有了影响
如【1, 1, 2】,当插入2后,因为取出元素是从开头取的,所以2只能在1之后被取出,1对结果没有了影响
从队列尾部插入元素时,我们取出所有比它小的数字(即对结果没有影响的数字),这样整个队列保留的都是对结果有影响的数字,此时队列是单调递减的
维护一个单调递减的队列:在插入一个值时,取出所有比它小的数字即可
从队列尾部取出元素,使用双端队列
时间:均摊为1 ,虽然在push_back()中出现了一个循环,但每个元素最多入双端队列一次,出队一次,所以均摊时间复杂度为1
空间 N,两个队列
class MaxQueue {
Queue<Integer> queue;
Deque<Integer> maxQue;
public MaxQueue() {
queue = new LinkedList<>();
maxQue = new LinkedList<>();
}
public int max_value() {
if(queue.isEmpty())
return -1;
return maxQue.peekFirst();
}
public void push_back(int value) {
while(!maxQue.isEmpty() && value > maxQue.peekLast())
{
maxQue.pollLast();
}
maxQue.offerLast(value);
queue.offer(value);
}
public int pop_front() {
if(queue.isEmpty())
return -1;
int res = queue.poll();
if(res == maxQue.peekFirst())
{
maxQue.pollFirst();
}
return res;
}
}
4.相关知识
- 双端队列:接口Deque,继承Queue,使用LinkedList实现
offerFirst(),offerLast(), pollFirst(), pollLast(), peekFirst(), peekLast()