题目
请定义一个队列并实现函数 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
思路
用两个对象模拟队列,因为时间复杂度都是O(1),所以不使用遍历的方式,就有了如下思路:
- 一个队列queue存储所有数据,另一个队列deque维护每个阶段的最大值,就变成一个递减的队列,到时候最大值就是队首值,这样时间复杂度为O(1),所以这个队列是一个双端队列;
- 队尾入队:当要添加的数据比双端队列队尾值小时,直接入双端队列deque;如果要添加的数据比双端队列队尾值大时,用这个值“代替”队尾值,即把当前队尾值删掉,把这个要添加的数据入队,以此类推;
- 队首出队:比较queue和deque的队首值,如果相同,双端队列deque出队,否则deque不操作,按照题目要求,当queue为空时,返回-1;
- 获取队列最大值:按照题目要求,当deque为空时,返回-1,否则直接获取队首值即为最大值。
代码
var MaxQueue = function() {
// 存储队列数据
this.queue = {}
// 双端队列维护最大值(每个阶段的最大值)
this.deque = {}
// head队首 count队尾
this.headQ = this.headD = this.countQ = this.countD = 0
};
/** 队尾入队
* @param {number} value
* @return {void}
*/
MaxQueue.prototype.push_back = function(value) {
// 数据在queue入队
this.queue[this.countQ++] = value
// 检测是否可以将数据添加到双端队列
while(!this.isEmptyDeque() && value > this.deque[this.countD-1]){
delete this.deque[--this.countD]
}
// 要添加的数据比双端队列队尾值小,入队
this.deque[this.countD++] = value
};
/**队首出队
* @return {number}
*/
MaxQueue.prototype.pop_front = function() {
if(this.isEmptyQueue()){
// 题目要求
return -1
}
// 比较queue和deque的队首值,如果相同,双端队列deque出队,否则deque不操作
if(this.queue[this.headQ] === this.deque[this.headD]){
delete this.deque[this.headD]
this.headD++
}
// 获取到queue出队的值,并返回
const frontData = this.queue[this.headQ]
delete this.queue[this.headQ]
this.headQ++
return frontData
};
/**获取队列最大值
* @return {number}
*/
MaxQueue.prototype.max_value = function() {
if(this.isEmptyDeque()){
// 题目要求
return -1
}
return this.deque[this.headD]
};
MaxQueue.prototype.isEmptyQueue = function(){
return this.countQ - this.headQ === 0
}
MaxQueue.prototype.isEmptyDeque = function(){
return this.countD - this.headD === 0
}