threedayAAAAA / alg-exercise

算法训练
0 stars 0 forks source link

【基础篇 - Day 5】 2023-02-17 - 232. 用栈实现队列 (01. 数组,栈,队列 ) #7

Open threedayAAAAA opened 1 year ago

threedayAAAAA commented 1 year ago

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):

实现 MyQueue 类:

void push(int x) 将元素 x 推到队列的末尾 int pop() 从队列的开头移除并返回元素 int peek() 返回队列开头的元素 boolean empty() 如果队列为空,返回 true ;否则,返回 false 说明:

你 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。  

示例 1:

输入: ["MyQueue", "push", "push", "peek", "pop", "empty"] [[], [1], [2], [], [], []] 输出: [null, null, null, 1, 1, false]

解释: MyQueue myQueue = new MyQueue(); myQueue.push(1); // queue is: [1] myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue) myQueue.peek(); // return 1 myQueue.pop(); // return 1, queue is [2] myQueue.empty(); // return false  

提示:

1 <= x <= 9 最多调用 100 次 push、pop、peek 和 empty 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)  

进阶:

你能否实现每个操作均摊时间复杂度为 O(1) 的队列?换句话说,执行 n 个操作的总时间复杂度为 O(n) ,即使其中一个操作可能花费较长时间。

来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/implement-queue-using-stacks 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

threedayAAAAA commented 1 year ago

思路

代码

class MyQueue {
    private data: number[]
    private data2: number[] 

    constructor() {
        this.data = []
        this.data2 = []
    }

    reverse(): void{
        while(this.data.length){
            this.data2.push(this.data.pop())
        }
    }

    push(x: number): void {
        this.data.push(x)
    }

    pop(): number {
        this.peek()
        return this.data2.pop()
    }

    peek(): number {
        if(this.empty()){
            return -1
        }
        if(!this.data2.length){
            this.reverse()
        }
        return this.data2[this.data2.length - 1]
    }

    empty(): boolean {
        return this.data.length + this.data2.length === 0
    }
}

时空复杂度

yunliuyan commented 1 year ago

思路

代码

class MyQueue {
    mainStack: number[];
    subStack: number[];
    constructor() {
        this.mainStack = [];
        this.subStack = [];
    }

    push(x: number): void {
        this.mainStack.push(x);
    }

    pop(): number {
        const res = this.peek();
        this.subStack.pop();
        return res;
    }

    peek(): number {
        // 如果辅助栈有元素,辅助栈栈顶先出
        if (this.subStack.length) {
            return this.subStack[this.subStack.length - 1];
        } else {
            while(this.mainStack.length) {
                this.subStack.push(this.mainStack.pop());
                if (!this.mainStack.length) {
                    return this.subStack[this.subStack.length - 1];
                }
            }
        }
    }

    empty(): boolean {
        return !(this.mainStack.length || this.subStack.length);
    }
}

复杂度分析

MiumMi commented 1 year ago

思路

  1. 声明两个数组,一个数组作为默认push填充的数组,另一个数组作为arr的倒序数组
  2. 在pop的时候,优先判断倒序数组是否有值,有的话直接pop出去(此时pop的是arr的首个填充的元素)
  3. 如果倒序数组没有值的话,则遍历arr,把当前arr所有元素pop进倒序数组(此时倒序数组的顺序则为arr的倒序)
  4. peek方法雷同,所以这里做下优化,在pop中先调用peek处理好倒序数组,然后再直接调用倒序数组的pop
  5. empty的判定则是两个数组均没有值才算是空数组

    代码

    
    class MyQueue {
    arr: number[];
    tempArr: number[];
    constructor() {
        this.arr = [];
        this.tempArr = [];
    }
    
    push(x: number): void {
        this.arr.push(x);
    }
    
    pop(): number {
        this.peek();
        return this.tempArr.pop();
    }
    
    peek(): number {
        if (this.empty()) {
            return;
        }
    
       if (!this.tempArr.length) {
            while(this.arr.length) {
                this.tempArr.push(this.arr.pop());
            }
        }
        return this.tempArr[this.tempArr.length - 1];
    }
    
    empty(): boolean {
        return !this.tempArr.length && !this.arr.length
    }
    }

/**