一、题目描述
小F玩套碗游戏,每个碗编号从1到n,按从大到小的顺序套在木棍上。每次只能从最上面取一个碗。给定一个取碗顺序,判断是否可以通过合法操作实现。
例子:
- 输入:
M = 2, a = [1, 2],输出:1(合法)。 - 输入:
M = 3, a = [3, 1, 2],输出:0(不合法)。 - 输入:
M = 4, a = [1, 3, 2, 4],输出:1(合法)。
二、解题思路
这类问题可以通过栈(stack)来模拟木棍的操作逻辑。栈符合先进后出的特点,非常适合用来表示套碗的顺序。
核心逻辑:
- 每次只允许从栈顶取出碗。
- 如果当前要取的碗不在栈顶,就需要按编号顺序将碗依次压入栈中,直到目标碗到达栈顶。
- 如果目标碗不能到达栈顶,说明顺序不合法。
三、具体实现步骤
- 定义一个空栈
stack。 - 设定变量
current = 1,表示下一个即将压入栈的碗编号。 - 遍历取碗顺序
a:- 如果当前碗在栈顶,直接弹出。
- 如果当前碗不在栈顶,则将
current到目标碗之间的碗依次压入栈,直到目标碗在栈顶,再弹出。 - 如果以上操作无法满足,返回
0(非法操作)。
- 如果遍历完成,返回
1(合法操作)。
四、代码实现
def solution(M: int, a: list) -> int:
stack = []
current = 1 # 表示即将压入栈的碗编号
for num in a:
# 压栈直到目标碗 num 出现在栈顶
while current <= M and (not stack or stack[-1] != num):
stack.append(current)
current += 1
# 如果目标碗在栈顶,则弹出
if stack and stack[-1] == num:
stack.pop()
else:
return 0 # 不合法,返回0
return 1 # 全部合法,返回1
五、测试与验证
# 测试用例
print(solution(2, [1, 2])) # 输出:1
print(solution(3, [3, 1, 2])) # 输出:0
print(solution(4, [1, 3, 2, 4])) # 输出:1
结果分析:
- 测试用例1:取碗顺序
[1, 2]可以按顺序依次压入弹出,合法。 - 测试用例2:取碗顺序
[3, 1, 2]中,碗1需要先于碗2被取出,但实际操作中无法实现,非法。 - 测试用例3:取碗顺序
[1, 3, 2, 4]可以通过依次压入和弹出实现,合法。
六、时间复杂度分析
- 压栈和弹栈操作:每个碗最多被压入和弹出一次,复杂度为 (O(M))。
- 总复杂度:由于遍历了整个取碗顺序数组,总体时间复杂度为 (O(M))。
七、总结与收获
- 栈的使用:栈非常适合模拟这类“先进后出”的问题。
- 问题建模:通过分析规则,将问题抽象为栈的压入和弹出过程。
- 边界条件:注意在每一步都需要检查目标碗是否在栈顶,或者是否已经压入栈中。
这道题巩固了栈在模拟现实问题中的应用,类似问题还可以扩展到括号匹配、文件路径解析等领域。