栈与队列 · 3/4

包含最小值的栈

实现一个能在 O(1) 时间获取最小值的栈

问题

设计一个栈,除了支持 pushpoptop 操作外,还能在 O(1) 时间内获取栈中的最小元素。

解答

思路

使用辅助栈同步记录每个状态下的最小值。每次 push 时,辅助栈存入当前最小值;pop 时两个栈同步弹出。

实现

class MinStack {
  constructor() {
    this.stack = []    // 数据栈
    this.minStack = [] // 辅助栈,存储对应位置的最小值
  }

  // 入栈
  push(val) {
    this.stack.push(val)
    // 辅助栈为空或新值更小,则存入新值;否则存入当前最小值
    if (this.minStack.length === 0) {
      this.minStack.push(val)
    } else {
      this.minStack.push(Math.min(val, this.getMin()))
    }
  }

  // 出栈
  pop() {
    this.stack.pop()
    this.minStack.pop()
  }

  // 获取栈顶元素
  top() {
    return this.stack[this.stack.length - 1]
  }

  // 获取最小值
  getMin() {
    return this.minStack[this.minStack.length - 1]
  }
}

测试

const stack = new MinStack()
stack.push(3)
stack.push(2)
stack.push(5)
console.log(stack.getMin()) // 2
stack.pop()
console.log(stack.getMin()) // 2
stack.pop()
console.log(stack.getMin()) // 3

优化:减少辅助栈空间

当新元素大于当前最小值时,辅助栈不入栈:

class MinStack {
  constructor() {
    this.stack = []
    this.minStack = []
  }

  push(val) {
    this.stack.push(val)
    // 只有小于等于当前最小值时才入辅助栈
    if (this.minStack.length === 0 || val <= this.getMin()) {
      this.minStack.push(val)
    }
  }

  pop() {
    // 弹出值等于最小值时,辅助栈也弹出
    if (this.stack.pop() === this.getMin()) {
      this.minStack.pop()
    }
  }

  top() {
    return this.stack[this.stack.length - 1]
  }

  getMin() {
    return this.minStack[this.minStack.length - 1]
  }
}

关键点

  • 辅助栈与数据栈同步操作,记录每个状态的最小值
  • 所有操作时间复杂度均为 O(1)
  • 优化版本:只在新值 ≤ 当前最小值时才入辅助栈,节省空间
  • 注意边界:辅助栈判断用 <= 而非 <,处理重复最小值的情况