返回

巧用两个栈,化栈为队:解LeetCode面试题03.04

前端

准备迎接一场算法思维的考验!在这场探索中,我们将利用JavaScript的栈结构来解决一道经典的面试题:03.04. 化栈为队。我们将会见证如何巧妙地将两个栈组合起来,模拟一个队列,以实现先进先出(FIFO)的行为。

队列与栈:概念解析

在深入探讨解决之道之前,让我们先回顾一下队列和栈这两种基本的数据结构。队列遵循先进先出(FIFO)原则,即先进入队列的元素也会先被移除。另一方面,栈遵循后进先出(LIFO)原则,即后进入栈的元素会先被移除,就像一摞盘子。

利用两个栈模拟队列

为了将栈转化为队列,我们需要利用两个栈:一个作为“push栈”,另一个作为“pop栈”。push栈负责模拟入队操作,而pop栈负责模拟出队操作。

入队操作

当我们需要入队一个元素时,我们只需将其压入push栈即可。push栈会充当队列的“后端”,新元素始终被添加到栈顶。

出队操作

当我们需要出队一个元素时,情况就稍微复杂一些了。如果pop栈为空,这意味着没有元素可以出队。为了解决这个问题,我们需要将push栈中的所有元素出栈并压入pop栈。此操作本质上将push栈中的元素逆序,从而在pop栈中实现先进先出的行为。

完整代码示例

下面是使用JavaScript实现的完整代码示例:

class Queue {
  constructor() {
    this.pushStack = [];
    this.popStack = [];
  }

  enqueue(element) {
    this.pushStack.push(element);
  }

  dequeue() {
    if (this.popStack.length === 0) {
      while (this.pushStack.length > 0) {
        this.popStack.push(this.pushStack.pop());
      }
    }
    return this.popStack.pop();
  }
}

应用示例

为了演示队列的实际应用,让我们考虑这样一个场景:我们有一组任务需要按顺序执行。每个任务由一个整数表示,较小的整数表示优先级较高的任务。

我们可以使用队列来管理这些任务,并确保优先级较高的任务先被执行。以下是如何使用我们实现的队列来解决这个问题:

const queue = new Queue();

// 添加任务
queue.enqueue(3);
queue.enqueue(1);
queue.enqueue(5);
queue.enqueue(2);

// 执行任务
while (!queue.isEmpty()) {
  const task = queue.dequeue();
  // 执行任务 task
}

通过这种方式,我们可以确保优先级较高的任务(即整数较小的任务)先被执行。

结论

使用两个栈来模拟队列是一种巧妙且高效的技术,可用于解决各种算法问题。它体现了数据结构的灵活性,以及如何在有限的工具下实现复杂的行为。掌握这种技术不仅有助于解决面试难题,而且在实际软件开发中也是一项宝贵的技能。