返回

以LeetCode 946题为例,剖析栈序列验证的艺术

前端

从理论到实践,剖析栈序列验证的奥秘

在软件开发中,栈是一种重要的数据结构,它遵循后进先出(LIFO)的原则。栈序列验证涉及判断一个给定的序列是否可以通过一系列推入和弹出操作从空栈生成。

为了理解栈序列验证的本质,让我们从一个简单的例子入手。假设我们有一个空栈,然后依次将元素1、2、3、4、5推入栈中,再依次弹出元素5、4、3、2、1,那么这个序列就是合法的栈序列。

然而,并非所有序列都是合法的栈序列。例如,序列1、2、3、4、5、4、3、2、1就不是合法的栈序列,因为在弹出元素4之前,栈中没有元素4,因此无法弹出。

LeetCode 946题:栈序列验证的经典案例

LeetCode 946题就是一道经典的栈序列验证题目。题目如下:

给定两个整数数组pushed和popped,其中pushed是栈的压入顺序,popped是栈的弹出顺序。如果pushed和popped序列都是有效序列并且popped序列是pushed序列的弹出序列,则返回true;否则,返回false。

例如,给定pushed=[1,2,3,4,5]和popped=[4,5,3,2,1],那么返回true,因为popped序列是pushed序列的弹出序列。

算法设计:借助辅助栈模拟压入弹出操作

为了解决LeetCode 946题,我们可以借助一个辅助栈来模拟压入和弹出操作。具体步骤如下:

  1. 创建一个辅助栈stack,并将其初始化为空。

  2. 遍历pushed数组,依次将元素压入stack中。

  3. 遍历popped数组,依次检查stack顶部的元素是否与当前要弹出的元素相等。如果相等,则将stack顶部的元素弹出。否则,返回false。

  4. 如果遍历完popped数组后,stack为空,则返回true,否则返回false。

代码实现:Python语言的简洁表达

使用Python语言,我们可以将上述算法设计转化为简洁的代码实现:

def validate_stack_sequences(pushed, popped):
  # 创建一个辅助栈
  stack = []

  # 遍历pushed数组,依次将元素压入stack中
  for i in range(len(pushed)):
    stack.append(pushed[i])

  # 遍历popped数组,依次检查stack顶部的元素是否与当前要弹出的元素相等
  for i in range(len(popped)):
    if stack[-1] == popped[i]:
      stack.pop()  # 将stack顶部的元素弹出
    else:
      return False  # 返回false

  # 如果遍历完popped数组后,stack为空,则返回true,否则返回false
  return len(stack) == 0


# 测试用例
test_cases = [
  ([[1, 2, 3, 4, 5], [4, 5, 3, 2, 1]]),
  ([[1, 2, 3, 4, 5], [4, 3, 5, 1, 2]]),
  ([[1, 2, 3, 4, 5], [4, 5, 3, 2, 1, 6]])
]

for pushed, popped in test_cases:
  result = validate_stack_sequences(pushed, popped)
  print(f"Input: pushed={pushed}, popped={popped}")
  print(f"Output: {result}")

复杂度分析:时间复杂度与空间复杂度

在上述算法中,时间复杂度主要取决于pushed和popped数组的长度n。遍历pushed和popped数组需要花费O(n)的时间,模拟压入和弹出操作也需要花费O(n)的时间,因此总的时间复杂度为O(n)。

空间复杂度主要取决于辅助栈stack的大小。在最坏情况下,stack的大小可能达到n,因此空间复杂度为O(n)。

结语:从LeetCode 946题洞悉栈序列验证的奥秘

LeetCode 946题是一个经典的栈序列验证题目,它考察了算法设计、数据结构和复杂度分析等方面的综合能力。通过对这道题目的剖析,我们不仅掌握了栈序列验证的算法和实现方法,也对栈这一重要数据结构有了更深入的理解。