azarasi / LeetCode 608. Tree Node

Created Thu, 07 Apr 2022 12:05:45 +0800 Modified Wed, 18 Sep 2024 14:00:22 +0000

Table: Tree

Column NameType
idint
p_idint

id is the primary key column for this table. Each row of this table contains information about the id of a node and the id of its parent node in a tree. The given structure is always a valid tree.

Each node in the tree can be one of three types:

  • “Leaf”: if the node is a leaf node.
  • “Root”: if the node is the root of the tree.
  • “Inner”: If the node is neither a leaf node nor a root node.

Write an SQL query to report the type of each node in the tree.

Return the result table ordered by id in ascending order.

The query result format is in the following example.

Example 1:

Input: Tree table:

idp_id
1null
21
31
42
52

Output:

idtype
1Root
2Inner
3Leaf
4Leaf
5Leaf

Explanation: Node 1 is the root node because its parent node is null and it has child nodes 2 and 3. Node 2 is an inner node because it has parent node 1 and child node 4 and 5. Nodes 3, 4, and 5 are leaf nodes because they have parent nodes and they do not have child nodes.

Example 2:

Input: Tree table:

idp_id
1null

Output:

idtype
1Root

Explanation: If there is only one node on the tree, you only need to output its root attributes.

方法 1:使用 UNION

想法我们可以按照下面的定义,求出每一条记录的节点类型。

  • Root: 没有父节点
  • Inner: 它是某些节点的父节点,且有非空的父节点
  • Leaf: 除了上述两种情况以外的节点

算法将上述定义转化,我们可以得到下面的代码。

根节点是没有父节点的节点。

SELECT id,
       'Root' AS Type
FROM tree
WHERE p_id IS NULL;

叶子节点是没有孩子节点的节点,且它有父亲节点。

SELECT id,
       'Leaf' AS Type
FROM tree
WHERE id NOT IN (
    SELECT DISTINCT p_id
    FROM tree
    WHERE p_id IS NOT NULL
)
  AND p_id IS NOT NULL;

内部节点是有孩子节点和父节点的节点。

SELECT id,
       'Inner' AS Type
FROM tree
WHERE id IN (
    SELECT DISTINCT p_id
    FROM tree
    WHERE p_id IS NOT NULL
)
  AND p_id IS NOT NULL;

所以本题的一种解法是将这些情况用 UNION 合并起来。

SELECT id,
       'Root' AS Type
FROM tree
WHERE p_id IS NULL
UNION
SELECT id,
       'Leaf' AS Type
FROM tree
WHERE id NOT IN (
    SELECT DISTINCT p_id
    FROM tree
    WHERE p_id IS NOT NULL
)
  AND p_id IS NOT NULL
UNION
SELECT id,
       'Inner' AS Type
FROM tree
WHERE id IN (
    SELECT DISTINCT p_id
    FROM tree
    WHERE p_id IS NOT NULL
)
  AND p_id IS NOT NULL
ORDER BY id;

方法 II:使用流控制语句 CASE

算法

与上面解法类似,本解法使用流控制语句,流控制语句对基于不同输入产生不同输出非常有效。

本方法中,我们使用 CASE 语句。

SELECT id      AS `Id`,
       CASE
           WHEN tree.id = (
               SELECT atree.id
               FROM tree atree
               WHERE atree.p_id IS NULL
           ) THEN 'Root'
           WHEN tree.id IN (
               SELECT atree.p_id
               FROM tree atree
           ) THEN 'Inner'
           ELSE 'Leaf'
           END AS Type
FROM tree
ORDER BY `Id`;

MySQL 除了 CASE 语句以外还提供了不同的流控制语句。

你可以尝试将上面的方法用 IF 重写。

方法 III;使用 IF 函数

算法

我们还可以使用 IF 函数来避免复杂的流控制语句。

SELECT atree.id,
       IF(
               ISNULL(atree.p_id),
               'Root',
               IF(
                           atree.id IN (
                           SELECT p_id
                           FROM tree
                       ),
                           'Inner',
                           'Leaf'
                   )
           ) Type
FROM tree atree
ORDER BY atree.id;