LeetCode每日一题——1570.设计前中后队列

105 阅读2分钟

1570.设计前中后队列

题目描述

请你设计一个队列,支持在前,中,后三个位置的 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] 。

 

示例 1:

输入:
["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 。

代码


class FrontMiddleBackQueue {
    private int[] pre, pst;
    private int prePre, prePst, pstPre, pstPst;
    private static final int max = 3000;
    public FrontMiddleBackQueue() {
        this.pre = new int[max];
        this.pst = new int[max];
        this.prePre = this.prePst = this.pstPre = this.pstPst = 0;
    }

    // 维护数组长度
    private void maintain(){
        int x = pstSize() - preSize();
        // 后比前长过1,后补前
        if(x > 1) pushPreBack(popPstFront());
        // 前比后长,前补后
        else if(x < 0) pushPstFront(popPreBack());
    }

    private boolean preEmpty(){
        if(this.prePst == this.prePre) return true;
        return false;
    }
    private boolean pstEmpty(){
        if(this.pstPst == this.pstPre) return true;
        return false;
    }

    // 前半段长度
    private int preSize(){
        if(this.prePst >= this.prePre) return this.prePst - this.prePre;
        else return max - this.prePre + this.prePst;
    }

    // 后半段长度
    private int pstSize(){
        if(this.pstPst >= this.pstPre) return this.pstPst - this.pstPre;
        else return max -this.pstPre + this.pstPst;
    }

    // 前插,先存后移
    public void pushFront(int val) {

        this.pre[this.prePst] = val;
        this.prePst = (this.prePst + 1) % max;
        maintain();
    }

    // 插入前半段的后插,先移后存
    private void pushPreBack(int val){
        this.prePre = this.prePre == 0 ? max - 1: this.prePre - 1;
        this.pre[this.prePre] = val;
    }

    // 中插
    public void pushMiddle(int val) {
        if(preSize() < pstSize()) pushPreBack(val);
        else pushPstFront(val);
        maintain();
    }

    // 后插,先存后移
    public void pushBack(int val) {
        this.pst[this.pstPst] = val;
        this.pstPst = (this.pstPst + 1) % max;
        maintain();
    }

    // 插入后半段的前插,先移后存
    private void pushPstFront(int val){
        this.pstPre = this.pstPre == 0 ? max - 1: this.pstPre - 1;
        this.pst[this.pstPre] = val;
    }

    // 先移再返回
    public int popFront() {
        if(preEmpty()) {
            if(pstEmpty()) return -1;
            return popPstFront();
        }

        if(this.prePst == 0) this.prePst = max;
        this.prePst--;
        maintain();
        return this.pre[this.prePst];
    }

    // 前半段的后面,先返回再移动
    private int popPreBack(){
        int flag = this.prePre;
        this.prePre = (this.prePre + 1) % max;
        return this.pre[flag];
    }

    public int popMiddle() {
        if(pstEmpty() && preEmpty()) return -1;
        if(preSize() < pstSize()) return popPstFront();
        else return popPreBack();
    }

    // 先移再返回
    public int popBack() {
        if(pstEmpty()) {
            if(preEmpty()) return -1;
            return popPreBack();
        }
        if(this.pstPst == 0) this.pstPst = max;
        this.pstPst--;
        maintain();
        return this.pst[this.pstPst];
    }
    // 后半段的前面,先返回再移动
    private int popPstFront(){
        int flag = this.pstPre;
        this.pstPre = (this.pstPre + 1) % max;
        return this.pst[flag];
    }
    // 方便debug
    public void show(){
        System.out.println("--------------------------------------------------------");
        System.out.println("前半段:头指针->"+this.prePst + ", 尾指针->" + this.prePre + ", 长度:" + preSize());
        System.out.println("后半段:头指针->"+this.pstPst + ", 尾指针->" + this.pstPre + ", 长度:" + pstSize());


        System.out.print("前:");
        for (int i = this.prePst; i != this.prePre; ) {
            if(preEmpty()) break;
            i = i == 0 ? max - 1 : i - 1;
            System.out.print(" ("+ this.pre[i] +")");
        }

        System.out.print(" || 后:");
        if(pstEmpty()) {
            System.out.println("\n--------------------------------------------------------");
            return;
        }
        for (int i = this.pstPre;;) {

            System.out.print(" ("+ this.pst[i] +")");
            i = (i + 1) % max;

            if(i == this.pstPst) break;
        }
        System.out.println("\n--------------------------------------------------------");

    }

}