LeetCode刷题,设计前中后队列(1670)

1,226 阅读3分钟

设计前中后队列

思路:使用两个双端队列来进行前中后插入,如queue1和queue2,当有插入时,判断两个队列元素数量是否相等。 不相等时往少的那个队列进行插入。始终保持两个队列元素相等或元素少一即可。

解题代码

  1. 首先创建一个链表节点类
  2. 然后创建一个队列类
  3. 最后创建两个双端队列,进行操作即可。
  4. 可用JS数组代替双端队列。
class MyNode { // 创建一个链表节点
  constructor(val,next = null,pre = null) {
    this.val = val;
    this.pre = pre;
    this.next = next;
  }
  
  insertPre(node) { // 在当前节点前插入节点
    node.pre = this.pre;
    node.next = this;
    if (this.pre) this.pre.next = node; // 如果当前节点存在,那么前一个节点,向后指向传入节点
    this.pre = node; // 当前节点向前指向传入节点 
  }

  insertNext(node) { // 在当前节点后插入节点
    node.pre = this; // 传入节点的前一位指向当前节点
    node.next = this.next; // 传入节点的下一位指向当前节点的下一位
    if (this.next) this.next.pre = node; // 如果下个节点存在,那么下个节点的前节点指向传入节点
    this.next = node; // 当前节点下个节点指向传入节点
  }

  deletePre() { // 删除当前节点前一个节点
    if (!this.pre) return;
    let p = this.pre; // 保存前一个节点
    this.pre = p.pre; // 向前再指向一步
    if (p.pre) p.pre.next = this; // 前前一个节点的下节点指向当前节点,此时即删除成功。
  }

  deleteNext() { //删除当前节点的下一个节点
    if (!this.next) return;
    let p = this.next; // 保存下一个节点
    this.next = p.next; // 向后指向一步
    if (p.next) p.next.pre = this; // 下下一个节点的前一个节点指向当前节点,此时即删除成功。
  }
}

class MyQueue { // 使用链表创建一个双端队列
  
  constructor() {
    const head = new MyNode(); 
    const tail = new MyNode();
    this.head = head // 头指针
    this.tail = tail // 尾指针
    this.head.next = this.tail; // 头尾互相指向
    this.head.pre = null; // 当前节点的前一个节点初始化为空
    this.tail.next = null;
    this.tail.pre = this.head; // 头尾互相指向
    this.cnt = 0; // 记录元素数量
  }

  pushBack(val) { // 从尾部入队
    this.tail.insertPre(new MyNode(val));
    this.cnt += 1;
  }

  pushFront(val) { // 从头部入队
    this.head.insertNext(new MyNode(val));
    this.cnt += 1;
  }

  popBack() { // 从尾部出队
    if (this.isEmpty()) return -1;
    let ret = this.tail.pre.val; // 被删除元素
    this.tail.deletePre();
    this.cnt -= 1;
    return ret;
  }

  popFront() { // 从头部出队
    if (this.isEmpty()) return -1;
    let ret = this.head.next.val; // 被删除元素
    this.head.deleteNext(); 
    this.cnt -= 1;
    return ret;
  }

  front() { // 查看头部元素
    return this.head.next.val;
  }

  back() { // 查看尾部元素
    return this.tail.pre.val;
  }

  isEmpty() { // 判空
    return this.head.next === this.tail; // 头尾指针指向同一个地址代表为空
  }

  size() {
    return this.cnt;
  }
}

// 思路:使用两个双端队列来进行前中后插入,如queue1和queue2,当有插入时,判断两个队列元素数量是否相等
// 不相等时往少的那个队列进行插入。始终保持两个队列元素相等或元素少一即可。
var FrontMiddleBackQueue = function() {
  this.queue1 = new MyQueue(); // 创建两个队列
  this.queue2 = new MyQueue();
};

/** 
 * @param {number} val
 * @return {void}
 */
FrontMiddleBackQueue.prototype.pushFront = function(val) {
  this.queue1.pushFront(val); // 从q1头部插入
  this.update();
};

/** 
 * @param {number} val
 * @return {void}
 */
FrontMiddleBackQueue.prototype.pushMiddle = function(val) {
  if (this.queue1.size() > this.queue2.size()) {
    this.queue2.pushFront(this.queue1.popBack()) // 移动元素位置
  }
  this.queue1.pushBack(val);
};

/** 
 * @param {number} val
 * @return {void}
 */
FrontMiddleBackQueue.prototype.pushBack = function(val) {
  this.queue2.pushBack(val); // 往q2尾部插入
  this.update();
};

/**
 * @return {number}
 */
FrontMiddleBackQueue.prototype.popFront = function() {
  if (this.isEmpty()) return -1;
  let ret = this.queue1.popFront(); //从q1头部删除
  this.update();
  return ret;
};

/**
 * @return {number}
 */
FrontMiddleBackQueue.prototype.popMiddle = function() {
  // 因为q1和q2的关系是,q1要不等于q2要不多一个,所以从中间出队永远是从q1尾部删除。  
  if (this.isEmpty()) return -1;
  let ret = this.queue1.popBack();
  this.update();
  return ret;
};

/**
 * @return {number}
 */
FrontMiddleBackQueue.prototype.popBack = function() {
  if (this.isEmpty()) return -1;
  let ret;
  if (this.queue2.isEmpty()){
    ret = this.queue1.popBack();
  } else {
    ret = this.queue2.popBack(); // 删除应该从q2末尾开始
  }
  this.update();
  return ret;
};

FrontMiddleBackQueue.prototype.update = function() { // 更新队列元素数量,如果偶数个,两个队列平分,奇数个,那么q1多一个
  if (this.queue1.size() < this.queue2.size()) {
    this.queue1.pushBack(this.queue2.front()) // 把q2头部元素添加到q1尾部
    this.queue2.popFront();
  }
  if(this.queue1.size() === this.queue2.size() + 2){
    this.queue2.pushFront(this.queue1.back()); // 把q1尾部元素添加到q2头部
    this.queue1.popBack();
  }
};

FrontMiddleBackQueue.prototype.isEmpty = function() {
  return this.queue1.size() === 0; // 因为q1一定会比q2多一个元素,所以q1不存在就代表队列为空
};


/**
 * 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()
 */