Skip to content

225.用队列实现栈

一、问题描述

实现一个栈,该栈使用两个队列作为内部存储结构。栈的主要操作包括:

  • push(x):将元素 x 推入栈顶。
  • pop():移除栈顶元素。
  • top():返回栈顶元素。
  • empty():检查栈是否为空。

二、方案一:使用一个队列

1、思路

设计思路:队首变成最后一个加入的元素

push 操作:将元素加入到队列中

top 操作:将队列中的前 n-1 个元素出队并重新加入队列

2、代码实现

go
type MyStack struct {
    queue []int
}
func Constructor() MyStack {
    return MyStack{}
}
func (this *MyStack) Push(x int) {
    this.queue = append(this.queue, x)
}
func (this *MyStack) Pop() int {
    n := len(this.queue)
    // 将队列中的前 n-1 个元素出队并重新加入队列
    for i := 0; i < n-1; i++ {
        this.queue = append(this.queue, this.queue[0])
        this.queue = this.queue[1:]
    }
    // 队首变成最后一个加入的元素
    top := this.queue[0]
    this.queue = this.queue[1:]
    return top
}
func (this *MyStack) Top() int {
    top := this.Pop()
    this.Push(top)
    return top
}
func (this *MyStack) Empty() bool {
    return len(this.queue) == 0
}

3、复杂度分析

  • 时间复杂度:Push 是 O(1),PopTop 是 O(n)。
  • 空间复杂度:O(n),因为我们需要额外的空间来存储队列中的元素。

三、方案二:使用两个队列

1、思路

设计思路:队列 1 用于存储元素,进行入队列和出队列;队列 2 用于纯辅助操作

push 操作:将元素加入到队列 1

pop 操作:将队列 1 的前 n - 1 个元素转移到 辅助队列2 中,然后移除剩下的一个元素,然后交换 队列1 和 队列 2

2、代码实现

Pop 操作使用辅助队列

go
type MyStack struct {
    queue1, queue2 []int
}
func Constructor() MyStack {
    return MyStack{}
}
func (this *MyStack) Push(x int) {
    this.queue1 = append(this.queue1, x)
}
func (this *MyStack) Pop() int {
	// 将队列 1 的前 n - 1 个元素转移到 辅助队列2 
    for len(this.queue1) > 1 {
        this.queue2 = append(this.queue2, this.queue1[0])
        this.queue1 = this.queue1[1:]
    }
    top := this.queue1[0]
    // 移除剩下的一个元素
    this.queue1 = this.queue1[1:]
    // 交换 队列1 和 队列 2
    this.queue1, this.queue2 = this.queue2, this.queue1
    return top
}
func (this *MyStack) Top() int {
    top := this.Pop()
    this.queue1 = append(this.queue1, top)
    return top
}
func (this *MyStack) Empty() bool {
    return len(this.queue1) == 0
}

Push 操作使用辅助队列

go
type MyStack struct {
    queue1, queue2 []int
}

/** Initialize your data structure here. */
func Constructor() (s MyStack) {
    return
}

/** Push element x onto stack. */
func (s *MyStack) Push(x int) {
    s.queue2 = append(s.queue2, x)
    for len(s.queue1) > 0 {
        s.queue2 = append(s.queue2, s.queue1[0])
        s.queue1 = s.queue1[1:]
    }
    s.queue1, s.queue2 = s.queue2, s.queue1
}

/** Removes the element on top of the stack and returns that element. */
func (s *MyStack) Pop() int {
    v := s.queue1[0]
    s.queue1 = s.queue1[1:]
    return v
}

/** Get the top element. */
func (s *MyStack) Top() int {
    return s.queue1[0]
}

/** Returns whether the stack is empty. */
func (s *MyStack) Empty() bool {
    return len(s.queue1) == 0
}

3、复杂度分析

  • 时间复杂度:Push 是 O(1),PopTop 是 O(n)。
  • 空间复杂度:O(n),因为我们需要额外的空间来存储两个队列中的元素。

四、总结

虽然使用两个队列在 poptop 操作时稍微优化了时间复杂性,但总体来说,两种方法的时间复杂性相似。选择哪种方法取决于具体的应用场景和性能需求。在大多数情况下,使用一个队列的方法因为更简单而更受欢迎。

木川工作室 (微信:mcmc2024)