题目重点:先按 task_id/parent_id 建树,再用祖先是否最后一个子节点决定缩进和 ├─/└─ 输出。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- task_id 在本训练版唯一,父记录可以出现在子记录之后;timestamp 仅作兄弟排序键,若题面按输入顺序则改为原始 index。
- 孤儿 parent_id、重复 ID、父子环按无效输入报告;如果面试题允许暂存孤儿,则需另定义输出时机。
- 同 timestamp 兄弟按输入位置稳定排序,多个 root 也按 (timestamp,index) 输出;题目未明确 tie-break。
解题路线
- 第一遍解析并验证字段数,把每条记录放进 id→node;保留 timestamp、原始 index、name、parent_id。不要遇到 child 就立刻打印,否则父节点可能稍后才出现。
- 第二遍按 parent_id 把 child 放入父的 children,把无 parent_id 的作为 root;检查父存在、自环和环路,可用 DFS 三色或入度计数。
- 对每组 children 先按题面排序。递归或显式栈输出:根行直接打印 task_name;子行使用传入的祖先延续前缀加 ├─ 或 └─。对非最后的祖先后代保留竖线与空格,对最后的祖先后代只留空格,使多层树不串线。
- 输出格式按代码点与空格精确比较。测试单根、多根、只有一个 child、深链、先子后父、两个兄弟嵌套、同 timestamp、孤儿和环。
手动走一遍
训练例 root R 有 A、B 两个 child,A 又有 A1:输出 R 换行 `├─A`、`│ └─A1`、`└─B`。A 非末子,所以 A1 前仍有竖线;B 是末子,其后代前不得延续 R 的竖线。实际是否有空格在连接符后,需按题面输出样例调整。
规模与取舍
N 条记录:建索引/连边期望 O(N),各兄弟列表排序总最坏 O(N log N),遍历输出 O(N+字符输出量),空间 O(N+树深)。若按输入顺序且无需排序,可 O(N)。
易错点与追问
容易失分的边界
- 边解析边打印,后到的父记录让孩子顺序/缩进出错。
- 只看本节点是否最后一个,不记录祖先情况,多层树的竖线错误。
- 重复 task_id 静默覆盖,或者孤儿被当成新 root。
- 没有环检测导致递归无限循环。
- 把未公开的第三段需求编成当前题目的确定规则。
继续深挖
- 记录源是流式且父子乱序,什么时候能安全输出一个已完成子树?
- 百万级深链如何避免递归栈溢出?
- 若 timestamp 会被修正,如何稳定重排兄弟而不重建所有节点?
