Topic describes

Design a queue that supports push and POP operations in the front, middle, and back positions.

Please complete the FrontMiddleBack class:

FrontMiddleBack() initializes the queue. Void pushFront(int val) adds val to the front of the queue. Void pushMiddle(int val) adds val to the middle of the queue. Void pushBack(int val) adds val to the end of the queue. Int popFront() removes the uppermost element from the queue and returns the value, or -1 if the queue was empty before the deletion. Int popMiddle() removes the middle element from the queue and returns the value, or -1 if the queue was empty before deletion. Int popBack() removes the last element from the queue and returns the value, or -1 if the queue was empty before deletion.

Note that when there are two middle positions, select the front position for operation. For example:

Add 6 to the middle of [1, 2, 3, 4, 5], resulting in an array of [1, 2, 6, 3, 4, 5].

Pop the element from the middle of [1, 2, 3, 4, 5, 6], return 3, and the array becomes [1, 2, 4, 5, 6].

Thought analysis

We can solve this problem by designing a two-endian queue, which we did before, two two-endian queues to form a front, middle and back queue.

The first and second double-endian queues can be designed to pushMiddle to the end of the first double-endian queue if they are equal, and to put data at the head of the second if the first queue is larger than the second.

So what we’re going to do in this problem is we’re going to encapsulate a double-ended queue, and we can also encapsulate a double-ended queue using a linked list.

So we can implement a list structure, and then use the list to implement a two-ended queue, and then implement this problem.

All right, Russian nesting dolls.

Next, we will implement the encapsulation of linked lists.

Can not transfer the position to learn the chain list, rice to eat a mouthful, the road to go step by step.

List enclosed

Create a TreeNode class with properties pre, Next, and Val.

Contains:

Insert_pre, insert_next, delete_pre, delete_next

insert_pre

insert_next

delete_pre

delete_next


class TreeNode {
    constructor(val, next, pre) {
        this.val = val;
        this.next = next;
        this.pre = pre;
    }
    
    insert_pre = (node) = > {
        node.next = this;
        node.pre = this.pre;
        if (this.pre) {
            this.pre.next = node
        }
        this.pre = node;
        return;
    }
    
    insert_next = (node) = > {
        next.pre = this;
        next.next = this;
        if (this.pre) this.next.pre = node;
        this.next = node;
    }
    
    delete_pre = () = > {
        if (!this.pre) return;
        const node = this.pre;
        this.pre = node.pre;
        if (node.pre) node.pre.next = this;
        return;
    }

    delete_next = () = > {
        if (!this.next) return;
        const node = this.next;
        this.next = node.next;
        if (node.next) node.next.pre = this;
        return; }}Copy the code

Double-ended queue encapsulation using linked lists

First, a two-endian queue needs to have two nodes, head and tail

At initialization, the first node above the head node is empty, the next node after the tail node is empty, and the next node after the head node is the tail node, and the last node is the head node.

I’m done with dolls! Take a look at the separate implementation of dual – ended queue encapsulation

In addition, there is an auxiliary parameter, count, which stores the size of the current two-ended queue

The class name of a double-ended queue is called DeQueue, and the properties are covered above, so let’s look at the methods needed for a double-ended queue

pushBack

Insert a new object for the virtual tail node

pushFount

Inserts a new object for the virtual header node

popBack

Delete tail nodes

popFront

Delete header node

isEmpty

Empty queue

size

Queue size

front

View the header node

back

View the tail node

Code to arrange

So let’s do that in code


class DeQueue {
    constructor() {
        this.head = new TreeNode();
        this.tail = new TreeNode();
        this.head.next = this.tail;
        this.tail.pre = this.head;
        this.head.pre = null;
        this.tail.next = null;
        this.count = 0;
    }
    
    pushBack = (val) = > {
        this.tail.insert_pre(new TreeNode(val));
        this.count += 1;
    }
    
    pushFront = (val) = > {
         this.head.insert_next(new TreeNode(val));
         this.count += 1;
    }
    
    popBack = () = > {
        if (this.isEmpty()) return;
        const ret = this.tail.pre.val;
        this.tail.delete_pre();
        this.count -= 1;
        return ret;
    };

    popFront = () = > {
        if (this.isEmpty()) return;
        const ret = this.head.next.val;
        this.head.delete_next();
        this.count -= 1;
        return ret;
    };

    isEmpty = () = > {
        return this.head.next === this.tail;
    };

    size = () = > {
        return this.count;
    };

    front = () = > {
        return this.head.next.val;
    };

    back = () = > {
        return this.tail.pre.val;
    };
}

Copy the code

Implement our front, middle and back queues using encapsulated double-ended queues

Need to achieve the title has been described, ideas in the beginning of this article about the need to use two double-ended queues to achieve, in addition to normal to achieve our demand method, for the balance of two double-ended queue data we can add an update method.

The update () method is used to update the number of elements in two queues

Let’s implement our FrontMiddleBackQueue


class FrontMiddleBackQueue {
      constructor() {
          this.q1 = new DeQueue();
          this.q2 = new DeQueue();
      }

      // Two double-ended queues Q1 Q2
      // @lc code=start
      / * * *@param {number} val
       * @return {void}* /
      pushFront = (val) = > {
          this.q1.pushFront(val);
          this.update();
          return;
      };

      / * * *@param {number} val
       * @return {void}* /
      pushBack = (val) = > {
          this.q2.pushBack(val);
          this.update();
          return;
      };

      / * * *@param {number} val
       * @return {void}* * /
      pushMiddle = (val) = > {
          if (this.q1.size() > this.q2.size()) {
            this.q2.pushFront(this.q1.popBack());
          }

          this.q1.pushBack(val);
          this.update();
          return;
      };

      / * * *@return {number}* /
      popFront = () = > {
          if (this.isEmpty()) return -1;
          const ret = this.q1.popFront();
          this.update();
          return ret;
      };

      / * * *@return {number}* /
      popBack = () = > {
          if (this.isEmpty()) return -1;
          let ret;
          if (this.q2.isEmpty()) {
            ret = this.q1.popBack();
          } else {
            ret = this.q2.popBack();
          }
          this.update();
          return ret;
      };

      / * * *@return {number}* /
      popMiddle = () = > {
          if (this.isEmpty()) return -1;
          const ret = this.q1.popBack();
          this.update();
          return ret;
      };

      isEmpty = () = > {
          return this.q1.size() + this.q2.size() === 0;
      };

      update = () = > {
          // Update the number of elements Q1, odd, even evenly divided
          if (this.q1.size() < this.q2.size()) {
            this.q1.pushBack(this.q2.popFront());
          }

          if (this.q1.size() === this.q2.size() + 2) {
            this.q2.pushFront(this.q1.popBack()); }}; }Copy the code

Other related

Full code implementation