订阅更新

判断树节点类型:根、内部节点还是叶子

SQL 实战 123 题 · 第 36 题 中等 约 2 分钟读完

LeetCode 608 · CASE WHEN、NOT IN 与 NULL、自关联

本文目录
  1. 面试怎么回答
  2. 题意
  3. 表结构
  4. 思路
  5. 参考解法
  6. 易错点

面试怎么回答

用 CASE 按顺序判断:p_id 为空是根;id 出现在别人的 p_id 里是内部节点;否则是叶子。我会特意说明子查询里有 NULL 时 NOT IN 会失效,所以要么过滤掉 NULL、要么用 IN 判断「有孩子」,单节点的树按 CASE 顺序会先判为根。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

题意

树表每行是一个节点和它的父节点编号。输出每个节点的类型:没有父节点的是根;有父节点但没有子节点的是叶子;其余是内部节点。按节点编号排序。

表结构

  • tree:id(主键)、p_id(父节点,根节点为空)

思路

用 CASE 按优先级判断:先判断 p_id 为空则是根;否则看它的 id 是否出现在任何节点的 p_id 里,出现了说明有孩子,是内部节点,没出现就是叶子。原解法用了 IFNULL(p_id, 0) 把子查询里的 NULL 替换掉,这是为了避开 NOT IN 遇到 NULL 全部失效的坑。

参考解法

select id,
    (case when p_id is null then "Root"
    when id not in (select ifnull(p_id,0) from tree) then "Leaf"
    else "Inner" end)  Type
from tree

另一种写法:用 IN 判断「有孩子」,避开 NOT IN 的 NULL 问题

SELECT id,
  CASE WHEN p_id IS NULL THEN 'Root'
       WHEN id IN (SELECT p_id FROM tree WHERE p_id IS NOT NULL) THEN 'Inner'
       ELSE 'Leaf' END AS Type
FROM tree
ORDER BY id

易错点

  • id NOT IN (SELECT p_id FROM tree) 子查询里有根节点的 NULL,结果全是 UNKNOWN,一个叶子都判断不出来。
  • CASE 的顺序很重要:只有一个节点的树,它既没父也没子,应该判为根,所以根的判断要放在最前面。
刷题进度保存在当前浏览器