力扣日记10.7-【栈与队列篇】用栈实现队列

力扣日记:【栈与队列篇】用栈实现队列

日期:2023.
参考:代码随想录、力扣

232. 用栈实现队列

题目描述

难度:简单

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(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) ,即使其中一个操作可能花费较长时间。

题解

cpp ver
class MyQueue {
public:
    // stack 的四种方法:pop(), push(), top(), empty()
    stack<int> stIn;
    stack<int> stOut;
    MyQueue() { // 这是构造函数

    }
    
    void push(int x) {
        stIn.push(x); // 推的话直接推到输入栈即可
    }
    
    int pop() {
        // 如果输出栈为空,要先把所有元素都推到输出栈,再从输出栈导出(让输入栈底部的元素回到输出栈顶部)
        if (stOut.empty()) {
            while (!stIn.empty()) {
                stOut.push(stIn.top()); // stack 的 pop() 不会返回元素?
                stIn.pop();
            }
        } 
        // 如果输出栈不为空,则直接从输出栈弹出即可
        int res = stOut.top();
        stOut.pop(); // 先获取顶部值,再弹出(否则无法访问到)
        return res;   
    }
    
    int peek() {
        // peek() 与 pop() 的操作类似,只是不需要导出
        int res = this->pop(); // 先推出
        stOut.push(res);    // 再推回去(注意这里推回去要推回输出栈(因为是从输出栈推出的,而不能用this->push(),这是推到输入栈)
        return res;
    }
    
    bool empty() {
        if (stIn.empty() && stOut.empty()) { // 当输入栈和输出栈都为空,则为空
            return true;
        }
        return false;
    }
};

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue* obj = new MyQueue();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->peek();
 * bool param_4 = obj->empty();
 */
go ver
type MyQueue struct {
    // go 中slice可用来作为栈(可方便地在末尾添加和删除元素)
    stIn    []int
    stOut   []int
}


func Constructor() MyQueue { // Constructor()为函数名,MyQueue 为返回值类型
    // 在构造函数中初始化一个对象(其中对stIn和stOut申请内存空间)
    return MyQueue{
        stIn:  make([]int, 0),
        stOut: make([]int, 0),
    }
}


func (this *MyQueue) Push(x int)  {
    this.stIn = append(this.stIn, x)
}


func (this *MyQueue) Pop() int {
    if len(this.stOut) == 0 {
        for len(this.stIn) > 0 {
            this.stOut = append(this.stOut, this.stIn[len(this.stIn) - 1]) // 获取stIn最后一个元素并推入stOut
            this.stIn = this.stIn[:len(this.stIn) - 1] // 删除最后一个元素
        }
    }
    res := this.stOut[len(this.stOut) - 1]
    this.stOut = this.stOut[:len(this.stOut) - 1]
    return res
    // 或
    /*
    inLen, outLen := len(this.stackIn), len(this.stackOut)
    if outLen == 0 {
        if inLen == 0 {
            return -1
        }
        for i := inLen - 1; i >= 0; i-- {
            this.stackOut = append(this.stackOut, this.stackIn[i]) // 每次仅改变访问的位置即可,最后再清空
        }
        this.stackIn = []int{}      //导出后清空
        outLen = len(this.stackOut) //更新长度值
    }
    val := this.stackOut[outLen-1]
    this.stackOut = this.stackOut[:outLen-1]
    return val
    */
}


func (this *MyQueue) Peek() int {
    // 重用 pop() 
    res := this.Pop()
    this.stOut = append(this.stOut, res)
    return res
}


func (this *MyQueue) Empty() bool {
    if len(this.stIn) == 0 && len(this.stOut) == 0 {
        return true;
    } else {
        return false;
    }
    // return len(this.stackIn) == 0 && len(this.stackOut) == 0
}


/**
 * Your MyQueue object will be instantiated and called as such:
 * obj := Constructor();
 * obj.Push(x);
 * param_2 := obj.Pop();
 * param_3 := obj.Peek();
 * param_4 := obj.Empty();
 */

复杂度

时间复杂度: push和empty为O(1), pop和peek为O(n)
空间复杂度: O(n) // 要申请两个栈来存放

思路总结

  • 栈在C++中的数据类型为 stack。其常用方法如下
    • push():将元素压入栈
    • pop():将栈顶部元素推出栈(但不会返回元素)
    • top():访问栈顶部元素
    • empty():判断栈是否为空
  • 要用栈实现队列,需要用到两个栈,一个作为输入栈,一个作为输出栈,如代码随想录的示意图
  • 其中,pop()操作需要借助输出栈:如果输出栈为空,要先把所有元素都推到输出栈,再从输出栈导出(让输入栈底部的元素回到输出栈顶部);如果输出栈不为空,则直接从输出栈弹出即可
  • peek()与pop()类似,可重用pop()代码,在pop()获得顶部元素后再将其push()回去,但要注意这里推回去要推回输出栈(因为是从输出栈推出的,而不能用this->push(),这是推到输入栈)

你可能感兴趣的:(leetcode,算法,职场和发展)