跳转至

5.5   练习

5.5.1   知识巩固

1.   栈和队列会先取出谁

准备一个空栈 S 和一个空队列 Q,分别对它们执行下面同一组操作:

步骤 1:加入 A; 步骤 2:加入 B; 步骤 3:移除一个元素并记录; 步骤 4:加入 C; 步骤 5:不断移除并记录,直到容器为空。

请分别写出 SQ 中元素被移除的顺序,并用“先入后出”或“先入先出”解释差异。

参考答案

S 的移除顺序是 B、C、A:加入 A、B 后先弹出最近加入的 B,再加入 C, 此后依次弹出 C、A,体现“先入后出”。

队列 Q 的移除顺序是 A、B、C:加入 A、B 后先移除最早加入的 A, 再加入 C,此后依次移除 B、C,体现“先入先出”。

2.   队尾越过数组末尾怎么办

用长度为 5 的环形数组实现队列,数组索引为 0~4。 当前 front = 3size = 2,队列中的 A、B 分别位于索引 3、4。

  1. 执行“C 入队”时,C 应放在哪个索引?入队后 size 是多少?
  2. 接着执行一次出队,弹出哪个元素?新的 frontsize 分别是多少?
  3. 此时从队首到队尾的逻辑顺序是什么?出队时是否需要移动数组中的其他元素?为什么?
参考答案
  1. 新元素的位置为 (front + size) % 5 = (3 + 2) % 5 = 0, 所以 C 放在索引 0。入队后 size = 3

  2. 出队弹出当前队首 A。新的队首索引为 (3 + 1) % 5 = 4,因此 front = 4size = 2

  3. 有效元素的逻辑顺序为 B、C,其中 B 位于索引 4,C 位于索引 0。 出队时只需移动 front 并修改 size,环形数组用取余让索引回到开头, 因此无须把其他元素整体向前移动。

3.   双向队列的两端操作

这里规定:push_first 表示从队首加入,push_last 表示从队尾加入, pop_first 表示从队首弹出,pop_last 表示从队尾弹出。

对一个空的双向队列 deq 依次执行:

  1. push_last(A)
  2. push_last(B)
  3. push_first(C)
  4. pop_last()
  5. push_last(D)
  6. pop_first()
  1. 两次弹出的元素分别是什么?
  2. 全部操作完成后,从队首到队尾还剩哪些元素?
  3. 检查这 6 步操作:只允许从队尾加入、从队首删除的队列能否全部完成?如果不能,请指出无法完成的操作;再说明双向队列能否完成及其原因。
参考答案

前三步后,双向队列从队首到队尾为 [C, A, B]

  1. pop_last() 弹出 B;加入 D 后队列为 [C, A, D]pop_first() 再弹出 C

  2. 最后剩下 [A, D]

  3. 只允许在队尾添加、在队首删除的队列不能完成全部操作: 第 3 步 push_first(C) 要求从队首加入,第 4 步 pop_last() 要求从队尾删除,都超出了这种队列的操作范围。 双向队列的两端都可以添加和删除,因此能够完成这 6 步操作。

5.5.2   编程练习

1.   检查括号序列

给定一个只包含 ()[]{} 这三类括号的字符串 s,请使用栈判断它是否合法。

合法序列须同时满足:每个右括号都必须与最近一个尚未配对的左括号类型匹配, 并且遍历结束后没有未配对的左括号。返回布尔值表示判断结果。

解题提示
  1. 可以建立“右括号到对应左括号”的映射
  2. 遇到右括号时,先检查栈是否为空,再检查栈顶是否匹配
  3. 遍历结束后,栈也必须为空

LeetCode 题目解析

欢迎在评论区留下你的见解、问题或建议