题目简述
请你设计一个队列,支持在前,中,后三个位置的 push 和 pop 操作。
请你完成 FrontMiddleBack 类:
- FrontMiddleBack() 初始化队列。
- void pushFront(int val) 将 val 添加到队列的 最前面 。
- void pushMiddle(int val) 将 val 添加到队列的 正中间 。
- void pushBack(int val) 将 val 添加到队里的 最后面 。
- int popFront() 将 最前面 的元素从队列中删除并返回值,如果删除之前队列为空,那么返回 -1 。
- int popMiddle() 将 正中间 的元素从队列中删除并返回值,如果删除之前队列为空,那么返回 -1 。
- int popBack() 将 最后面 的元素从队列中删除并返回值,如果删除之前队列为空,那么返回 -1 。
请注意当有 两个 中间位置的时候,选择靠前面的位置进行操作。比方说:
- 将 6 添加到 [1, 2, 3, 4, 5] 的中间位置,结果数组为 [1, 2, 6, 3, 4, 5] 。
- 从 [1, 2, 3, 4, 5, 6] 的中间位置弹出元素,返回 3 ,数组变为 [1, 2, 4, 5, 6] 。
示例
输入:
["FrontMiddleBackQueue", "pushFront", "pushBack", "pushMiddle", "pushMiddle", "popFront", "popMiddle", "popMiddle", "popBack", "popFront"]
[[], [1], [2], [3], [4], [], [], [], [], []]
输出:
[null, null, null, null, null, 1, 3, 4, 2, -1]
解释:
FrontMiddleBackQueue q = new FrontMiddleBackQueue();
q.pushFront(1); // [1]
q.pushBack(2); // [1, 2]
q.pushMiddle(3); // [1, 3, 2]
q.pushMiddle(4); // [1, 4, 3, 2]
q.popFront(); // 返回 1 -> [4, 3, 2]
q.popMiddle(); // 返回 3 -> [4, 2]
q.popMiddle(); // 返回 4 -> [2]
q.popBack(); // 返回 2 -> []
q.popFront(); // 返回 -1 -> [] (队列为空)
提示:
- 1 <= val <= 109
- 最多调用 1000 次 pushFront, pushMiddle, pushBack, popFront, popMiddle 和 popBack 。
javascript实现
// 用两个双端队列维护一个前中后队列
// 把一个队列分成两个双端队列,实现在中间位置插入元素
// 通过链表思想实现一个双端队列
// 实现双端队列实现需要虚拟头和虚拟尾
// 实现链表节点的结构,双向链表
function Node(val=0,next=null,pre=null) {
this.val = val;
this.next = next;
this.pre = pre
this.insert_pre = function(p){ // 实现在当前节点的前面插入一个新节点
p.pre = this.pre;
p.next = this;
if(this.pre) this.pre.next = p;
this.pre = p;
}
this.insert_next = function(p) { // 实现在当前节点的后面插入一个新节点
p.pre = this;
p.next = this.next;
if(this.next) this.next.pre = p;
this.next = p;
}
this.delete_pre = function() { // 实现删除当前的前一个节点
if(this.pre == null) return; //如果前面没节点了就直接返回
let p = this.pre;
this.pre = p.pre;
if(p.pre) p.pre.next = this;
}
this.delete_front = function() { // 实现删除当前的后一个节点
if(this.next == null) return; //如果后面没节点了就直接返回
let p = this.next;
this.next = p.next;
if(p.next) p.next.pre = this
}
}
// 通过链表节点实现一个双端队列
var Queue = function Queue() {// 双端队列构造函数
// 构造虚拟头和虚拟尾
this.head = new Node(0);
this.tail = new Node(0);
this.head.next = this.tail;
// this.head.pre = null;
// this.tail.next = null;
this.tail.pre = this.head;
this.count = 0
}
Queue.prototype.push_back = function(val) { // 从队尾添加
// 在虚拟尾的前面插入
this.tail.insert_pre(new Node(val))
this.count += 1
}
Queue.prototype.push_front = function(val) { // 从队头添加
// 在虚拟头的后面插入
this.head.insert_next(new Node(val))
this.count += 1
}
Queue.prototype.pop_back = function() { // 从队尾删除
// 删除先判空
if(this.isEmpty()) return -1;
let delVal = this.tail.pre.val;
this.tail.delete_pre()
this.count -= 1
return delVal
}
Queue.prototype.pop_front = function() { // 从队头删除
// 删除先判空
if(this.isEmpty()) return -1;
let delVal = this.head.next.val;
this.head.delete_front()
this.count -= 1
return delVal
}
Queue.prototype.get_front = function() { // 获取头部节点
return this.head.next.val
}
Queue.prototype.get_back = function() { // 获取尾部元素
return this.tail.pre.val
}
Queue.prototype.isEmpty = function() { // 判空
// 如果head.next == tail时, 链表只剩虚头和虚尾
return this.head.next == this.tail
}
Queue.prototype.size = function() { // 记录元素数量
return this.count;
}
// Queue.prototype.isFull = function(val) { // 判满
// // 用链表实现的话,本质是没有满的情况,因为链表是可以无线扩容的
// }
// 构造两个双端队列q1,q2
// q1 存前一半的元素,q2存后一半的元素
var FrontMiddleBackQueue = function() {
this.q1 = new Queue();
this.q2 = new Queue()
};
/**
* @param {number} val
* @return {void}
*/
FrontMiddleBackQueue.prototype.pushFront = function(val) {// 从最前面插入。q1的头部
this.q1.push_front(val)
this.updata() //更新元素数量。如果有偶数个元素就平分给q1、q2,如果实际数个就让q1多一个
};
/**
* @param {number} val
* @return {void}
*/
FrontMiddleBackQueue.prototype.pushMiddle = function(val) {
// 正常q1等于q2,或比q2多一个,
// 先判断q1是否大于q2,大于的话,就先把q1的尾元素添加到q2的头部
// 然后q1的尾部插入
if(this.q1.size() > this.q2.size()) {
this.q2.push_front(this.q1.get_back());
this.q1.pop_back()
}
this.q1.push_back(val)
};
/**
* @param {number} val
* @return {void}
*/
FrontMiddleBackQueue.prototype.pushBack = function(val) {
this.q2.push_back(val)
this.updata()
};
/**
* @return {number}
*/
FrontMiddleBackQueue.prototype.popFront = function() {
if(this.isEmpty()) return -1
let delVal = this.q1.pop_front();
this.updata()
return delVal
};
/**
* @return {number}
*/
FrontMiddleBackQueue.prototype.popMiddle = function() {
if(this.isEmpty()) return -1
// q1应该是大于等于q2的
// 删除q1尾部
let delVal = this.q1.pop_back()
this.updata()
return delVal
};
/**
* @return {number}
*/
FrontMiddleBackQueue.prototype.popBack = function() {
if(this.isEmpty()) return -1
let delVal = -1
// 如果q2为空
if(this.q2.isEmpty()) {
delVal = this.q1.pop_back()
}else {
delVal = this.q2.pop_back()
}
this.updata()
return delVal
};
FrontMiddleBackQueue.prototype.isEmpty = function() {
return this.q1.size() == 0; //q1的元素不少于q2
};
FrontMiddleBackQueue.prototype.updata = function() {
if(this.q1.size() < this.q2.size()){
this.q1.push_back(this.q2.get_front()); // 把q2的头部元素插入到q1的尾部
this.q2.pop_front(); // 并把q2头部元素删除
}
if(this.q1.size() == this.q2.size() + 2) { // 奇数个元素,q1比q2多一个;如果发现多两个了
this.q2.push_front(this.q1.get_back()); //把q1的尾元素添加到q2的头部
this.q1.pop_back()
}
};
/**
* Your FrontMiddleBackQueue object will be instantiated and called as such:
* var obj = new FrontMiddleBackQueue()
* obj.pushFront(val)
* obj.pushMiddle(val)
* obj.pushBack(val)
* var param_4 = obj.popFront()
* var param_5 = obj.popMiddle()
* var param_6 = obj.popBack()
*/