学习笔记:火车栈问题的解决方案
问题描述
在火车站中,小F观察到了火车驶入和驶出休息区的顺序。休息区类似于一个 栈 的结构,遵循 先进后出 的规则。每辆火车可以进入休息区,然后根据顺序驶出,小F想知道是否可以根据记录的驶入和驶出顺序来判断这些火车的操作是否符合栈的规则。
例如,给定火车的驶入顺序 [1, 2, 3],如果驶出顺序是 [3, 2, 1],则这是可能的,因为这符合栈的规则;但如果驶出顺序是 [3, 1, 2],则是不可能的。
问题分析
- 栈:栈是一种 后进先出 (LIFO) 的数据结构,即最后入栈的元素最先出栈。
- 模拟火车进出顺序:我们需要模拟火车的驶入和驶出顺序,以验证给定的驶出顺序是否合法。
解题思路
- 使用一个 栈 来模拟火车的进入休息区的过程。栈的操作正好符合火车的进入和退出逻辑。
- 遍历 驶入顺序 数组,将每一辆火车按顺序入栈。
- 每次将火车推入栈后,检查栈顶元素是否可以出栈,如果它和 驶出顺序 中的当前元素匹配,则将栈顶元素弹出。
- 如果能够按照驶出顺序全部出栈,则该顺序是可能的,否则则是不可能的。
代码实现
def solution(n, a, b):
stack = [] # 用于模拟火车的停留
j = 0 # 指向驶出序列 b 的索引
for i in range(n):
stack.append(a[i]) # 将火车驶入顺序中的火车入栈
# 检查栈顶元素是否和驶出顺序匹配
while stack and stack[-1] == b[j]:
stack.pop() # 如果匹配,则将栈顶元素出栈
j += 1 # 移动到 b 的下一个元素
# 如果栈为空,则说明所有火车都可以按 b 的顺序驶出
return len(stack) == 0
# 示例测试
print(solution(3, [1, 2, 3], [1, 2, 3])) # 输出:True
print(solution(3, [1, 2, 3], [3, 2, 1])) # 输出:True
print(solution(3, [1, 2, 3], [3, 1, 2])) # 输出:False
代码解释
-
初始化栈和索引:
stack用于模拟火车在休息区的停留。j是指向驶出顺序数组b的索引。
-
遍历火车驶入顺序:
- 每次将火车按照驶入顺序
a入栈。 - 检查栈顶元素是否与驶出顺序中的当前元素
b[j]匹配。如果匹配,则将栈顶元素出栈,并将索引j向后移动一位。
- 每次将火车按照驶入顺序
-
验证结果:
- 最终如果
stack为空,说明所有火车能够按给定的驶出顺序完成,返回True;否则返回False。
- 最终如果
示例分析
-
示例 1:
- 输入:
n = 3, a = [1, 2, 3], b = [1, 2, 3] - 输出:
True - 解释:火车按顺序驶入,按相同顺序驶出,符合规则。
- 输入:
-
示例 2:
- 输入:
n = 3, a = [1, 2, 3], b = [3, 2, 1] - 输出:
True - 解释:火车按顺序驶入,然后在休息区中按相反顺序驶出,符合栈的规则。
- 输入:
-
示例 3:
- 输入:
n = 3, a = [1, 2, 3], b = [3, 1, 2] - 输出:
False - 解释:火车 1 没有在火车 2 之前出栈,顺序无法匹配。
- 输入:
时间复杂度
- 时间复杂度:O(n)
- 代码遍历火车的驶入顺序一次,每个火车只会入栈和出栈各一次,所以整体的时间复杂度是 O(n),其中 n 为火车的数量。
空间复杂度
- 空间复杂度:O(n)
- 最坏情况下,所有火车都需要入栈,因此栈的空间复杂度为 O(n)。
总结
- 本题通过使用栈模拟火车进入和退出休息区的操作,验证了给定的驶入和驶出顺序是否符合栈的规则。
- 这种类型的题目可以很好地体现栈的 先进后出 特性,尤其是在需要模拟顺序、状态变化时,栈是非常合适的数据结构。
通过这个问题的学习,我们可以更好地理解栈在模拟场景中的应用,同时掌握如何判断复杂顺序是否合法的技巧。希望这篇学习笔记对你有所帮助!