返回

用栈优雅地实现 LeetCode 155:最小栈

前端

在编程的世界里,栈是一种基础而强大的数据结构,它以其后进先出 (LIFO) 的特性而闻名。在 LeetCode 155 中,我们面临着一项富有挑战性的任务:设计一个栈,它不仅可以执行基本的栈操作(push、pop、top),还能在常数时间内检索到栈中的最小元素。

拥抱优雅的解决方案

要解决这个问题,我们需要超越传统栈的范畴,探索更精妙的解决方案。让我们用两个栈来实现这个最小栈:

  • 主栈: 它将按 LIFO 顺序存储元素。
  • 辅助栈: 它将按递增顺序存储主栈中的最小元素。

每次向主栈添加一个元素时,我们也将其添加到辅助栈中,前提是该元素小于或等于辅助栈的栈顶元素。当我们从主栈中弹出元素时,如果该元素等于辅助栈的栈顶元素,我们也从辅助栈中弹出该元素。

这种设计确保了辅助栈的栈顶元素始终是主栈中的最小元素。因此,检索最小元素只需查看辅助栈的栈顶即可。

实现细节:

JavaScript:

class MinStack {
  constructor() {
    this.stack = [];
    this.minStack = [];
  }
  
  push(val) {
    this.stack.push(val);
    if (this.minStack.length === 0 || val <= this.minStack[this.minStack.length - 1]) {
      this.minStack.push(val);
    }
  }

  pop() {
    if (this.stack.length === 0) return null;
    const val = this.stack.pop();
    if (val === this.minStack[this.minStack.length - 1]) {
      this.minStack.pop();
    }
    return val;
  }

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

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

Python:

class MinStack:
  def __init__(self):
    self.stack = []
    self.min_stack = []

  def push(self, val):
    self.stack.append(val)
    if not self.min_stack or val <= self.min_stack[-1]:
      self.min_stack.append(val)

  def pop(self):
    if not self.stack: return None
    val = self.stack.pop()
    if val == self.min_stack[-1]:
      self.min_stack.pop()
    return val

  def top(self):
    return self.stack[-1] if self.stack else None

  def min(self):
    return self.min_stack[-1] if self.min_stack else None

Java:

import java.util.Stack;

public class MinStack {
  private Stack<Integer> stack;
  private Stack<Integer> minStack;

  public MinStack() {
    stack = new Stack<>();
    minStack = new Stack<>();
  }

  public void push(int val) {
    stack.push(val);
    if (minStack.isEmpty() || val <= minStack.peek()) {
      minStack.push(val);
    }
  }

  public int pop() {
    if (stack.isEmpty()) return -1;
    int val = stack.pop();
    if (val == minStack.peek()) {
      minStack.pop();
    }
    return val;
  }

  public int top() {
    return stack.peek();
  }

  public int min() {
    return minStack.peek();
  }
}

C++:

#include <stack>

class MinStack {
private:
  stack<int> stack;
  stack<int> minStack;
  
public:
  void push(int val) {
    stack.push(val);
    if (minStack.empty() || val <= minStack.top()) {
      minStack.push(val);
    }
  }
  
  int pop() {
    if (stack.empty()) return -1;
    int val = stack.top();
    stack.pop();
    if (val == minStack.top()) {
      minStack.pop();
    }
    return val;
  }
  
  int top() {
    return stack.top();
  }
  
  int min() {
    return minStack.top();
  }
};

优雅与效率的融合

这种双栈方法巧妙地将 LIFO 的便利性与快速检索最小元素的能力结合在一起。时间复杂度保持在 O(1) 的常数级别,从而确保了效率。

结论

通过超越传统栈的局限,我们创造了一个优雅而高效的解决方案,使 LeetCode 155 中的最小栈问题迎刃而解。这个双栈方法彰显了数据结构的创造性和适应性,展示了技术创新的力量。