请定义一个队列并实现函数 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来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/dui-lie-de-zui-da-zhi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
对于这道题我们同样可以采用和上一题相似的方法,维护一个deque队列来获得我们的最大值,也就是下面这篇博文中的第二种写法【LeetCode】【剑指offer】【滑动窗口的最大值(一)】_桜キャンドル淵的博客-CSDN博客
假设我们入队的顺序是这样的
0
1
2
3
4
5
6
13
9
2
3
2
5
7
6
2
那么我们的max_element双端队列就是9-7-6-2,如果新插入的元素比之前的大的话,将原来的队列中比新插入的元素小的数据全部都删除,最终就能得到我们这样的一个双端队列,这样如果要获取最大值就直接返回我们队首的元素就行了
那么在出队的时候,如果9出队了,我们的max_element中的9也要同时出队。但在2,3,2出队的时候,我们的max_element中的元素不用出队,因为7依旧是原来的队列中的最大值,只有当原队列中的7也出队的同时,我们的max_element的队首的7也要出队。
以此方式就能够得到我们想要的结果。
class MaxQueue {
public:
deque<int> max_element;
queue<int> queue;
MaxQueue() {
}
int max_value() {
if(!max_element.empty())
{
return max_element.front();
}
//队列为空就返回-1
return -1;
}
void push_back(int value) {
//如果队尾的元素比我们的插入的元素小就全部弹出
//保证我们维护最大值的队列中的数据是递减的。
while(!max_element.empty()&&max_element.back()<value)
{
max_element.pop_back();
}
//保证max_element中的数据元素的顺序和queue中的顺序是保持相对一致的。
max_element.push_back(value);
queue.push(value);
}
int pop_front() {
if(!queue.empty())
{
//如果我们当前弹出的是我们最大的那个元素
//我们需要将我们维护最大值的那个元素同时弹出
if(queue.front()==max_element.front())
{
max_element.pop_front();
}
int result=queue.front();
queue.pop();
return result;
}
return -1;
}
};
/**
* Your MaxQueue object will be instantiated and called as such:
* MaxQueue* obj = new MaxQueue();
* int param_1 = obj->max_value();
* obj->push_back(value);
* int param_3 = obj->pop_front();
*/
对于这道题我们可能会有猜想:这道题是否可以像上面那道题一样采用大根堆来维护我们的最大值呢?
当然没问题,只要我们给我们每次插入的数据加上一个索引就可以。然后再每次获取最大的元素的时候,查看一下当前的最大元素的索引是否还在队列内,如果不是就循环弹出,是的话就直接返回其值。
也就是类似于下面这篇博文中的第一种方法
class MaxQueue {
public:
priority_queue<pair<int,int>> max_queue;
queue<pair<int,int>> queue;
int index=0;
MaxQueue() {
}
int max_value() {
//如果我们的queue已经空了就返回-1
if(queue.empty())
{
return -1;
}
//如果我们的max_queue的队首元素的索引小于了queue的队首元素的索引,我们就要让其从堆中弹出
while(!max_queue.empty()&&max_queue.top().second<queue.front().second)
{
max_queue.pop();
}
//如果堆不空的话,就返回我们的堆顶的数据。
if(!max_queue.empty())
{
return max_queue.top().first;
}
//如果堆空了话就返回-1
return -1;
}
void push_back(int value) {
//同时插入数据和索引
max_queue.emplace(value,index);
queue.emplace(value,index);
//将索引++,为了存储下一次的数据
index++;
}
int pop_front() {
if(!queue.empty())
{
int tmp=queue.front().first;
queue.pop();
return tmp;
}
return -1;
}
};
/**
* Your MaxQueue object will be instantiated and called as such:
* MaxQueue* obj = new MaxQueue();
* int param_1 = obj->max_value();
* obj->push_back(value);
* int param_3 = obj->pop_front();
*/