SDET / SWE · Technical Fundamentals

TikTok 栈与队列:顺序契约、BFS/DFS和背压

从LIFO/FIFO选择遍历与调度结构,说明操作复杂度和并发任务队列边界。

题目重点:从LIFO/FIFO选择遍历与调度结构,说明操作复杂度和并发任务队列边界。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 讨论抽象栈队列及常见数组/链式实现,生产并发队列另外定义容量和确认政策。

解题路线

  1. 栈后进先出LIFO,适合未完成调用、括号解析、撤销历史和DFS;队列先进先出FIFO,适合BFS层序、按到达调度和生产消费缓冲。
  2. 选择依据是待处理任务的次序不变量。BFS无权最短路按距离逐层扩展,因此需要FIFO;换栈会变深搜,不能仍承诺首次到达为最短。
  3. 数组尾部push/pop实现栈常用,动态扩容使push摊还常量;用list.pop(0)做队列要移动元素,可用环形数组、双端队列或链表。实现选择决定实际成本。
  4. 任务队列的FIFO不等于处理完成顺序:多个worker并行消费会先完成后到任务。需要顺序结果时按partition串行或加入序列号与重排缓冲。
  5. 有界队列满时阻塞、拒绝、丢弃或降级须明确;无界队列只会把流量压力转成内存增长。确认、重试和去重决定交付语义,不能从“队列”二字推出恰好一次。
  6. 测试次序、空/满、并发关闭与取消、异常后是否还确认。算法题只需抽象接口,系统题要量化arrival/service速率与排队延迟。

手动走一遍

依次放a,b,c:栈取c,b,a,队列取a,b,c。两个worker队列先取a再b,但b耗时更短可先完成;这不违反取出FIFO,却影响业务顺序。

规模与取舍

常见链式/环形两端操作O(1),动态数组尾push摊还O(1),头部移动O(n)。积压Q项空间O(Q),负载持续超过服务率则无界增长。

易错点与追问

容易失分的边界

  • BFS使用栈仍说最短路。
  • FIFO等同完成顺序。
  • 无界队列当作解决过载。

继续深挖

  • 用两个栈实现队列如何摊还?
  • 优先级队列为何不属于FIFO?
  • 重试任务怎样防止重复副作用?
✓已复制微信号!