LeetCode 608 - Tree Node
This problem gives us a database table named Tree, where each row represents a node in a tree structure. Every node has a unique identifier id and a pid column that stores the identifier of its parent node.
Difficulty: 🟡 Medium
Topics: Database
Solution
Problem Understanding
This problem gives us a database table named Tree, where each row represents a node in a tree structure. Every node has a unique identifier id and a p_id column that stores the identifier of its parent node.
The task is to classify every node into one of three categories:
"Root"if the node has no parent, meaningp_id IS NULL"Leaf"if the node has no children"Inner"if the node has both a parent and at least one child
In simpler terms, we need to examine each node and determine its structural role inside the tree.
The input represents a valid tree. This guarantee is important because it means:
- There is exactly one root node
- There are no cycles
- Every non-root node has exactly one parent
- The relationships form a connected tree
The expected output is a result table containing two columns:
id, the node identifiertype, one of"Root","Leaf", or"Inner"
The order of the returned rows does not matter.
The key challenge is determining whether a node has children. The p_id column tells us who a node's parent is, but to know whether a node is a leaf or inner node, we must identify whether its id appears as another node's p_id.
Several edge cases are important to consider. A tree with only one node is both technically a root and a leaf, but the problem definition prioritizes "Root", so the correct classification is "Root". Another important case is nodes with children but no parent, which must always be labeled "Root". Finally, nodes with parents but no children are "Leaf" nodes.
Since this is a Database problem, the goal is to express this classification efficiently in SQL.
Approaches
Brute Force Approach
A straightforward way to solve this problem is to inspect each node independently and determine its type using repeated searches.
For every row in the Tree table, we could:
- Check whether
p_id IS NULL. If yes, classify it as"Root". - Otherwise, scan the table to see whether any row has
p_id = current id. - If children exist, classify it as
"Inner". - Otherwise, classify it as
"Leaf".
This approach is correct because every node is evaluated against the exact problem definition. However, it is inefficient because each node may require scanning the entire table to determine whether it has children.
If there are n nodes, checking children for each node takes O(n) work, producing a total complexity of O(n²).
Optimal Approach
The key observation is that we do not need to repeatedly search for child relationships. Instead, we can use a single query to identify all node IDs that appear as a parent.
A node is a parent if its id exists in the set of non-null p_id values.
Using SQL, this naturally translates into a CASE statement:
- If
p_id IS NULL, classify as"Root" - Else if
idexists among parent IDs, classify as"Inner" - Otherwise, classify as
"Leaf"
The important optimization is that the database can efficiently evaluate membership using a subquery or join, avoiding repeated manual scans.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n²) | O(1) | Repeatedly scans table for every node |
| Optimal | O(n) | O(n) | Uses parent ID lookup through subquery |
Algorithm Walkthrough
- Start by iterating through every node in the
Treetable. - For each node, first check whether
p_id IS NULL. This condition identifies the root node because a root has no parent. - If the node is not a root, determine whether it has children. We do this by checking whether the current node's
idappears in the set of all non-nullp_idvalues. If it appears there, it means at least one node references it as a parent. - If the node has children, classify it as
"Inner"because it is neither a root nor a leaf. - Otherwise, classify it as
"Leaf"because no node depends on it. - Return the result table with columns
idandtype.
Why it works
The correctness follows directly from the definitions of node types. Every node falls into exactly one of three mutually exclusive categories:
p_id IS NULLuniquely identifies the root.- A node appearing as a parent of another node must have children, making it an inner node unless it is the root.
- Any remaining node has no children, making it a leaf.
Because every node is classified according to these precise rules, the algorithm always produces the correct result.
Python Solution
Although this is a SQL problem on LeetCode, the platform sometimes requests a Python representation for consistency. The actual accepted solution is an SQL query.
class Solution:
def treeNode(self):
return """
SELECT
id,
CASE
WHEN p_id IS NULL THEN 'Root'
WHEN id IN (
SELECT DISTINCT p_id
FROM Tree
WHERE p_id IS NOT NULL
) THEN 'Inner'
ELSE 'Leaf'
END AS type
FROM Tree
"""
The implementation uses a SQL CASE expression to classify nodes.
The first condition checks p_id IS NULL, immediately identifying root nodes.
The second condition checks whether the node ID exists among parent IDs. The subquery retrieves all distinct non-null p_id values, which correspond to nodes that have at least one child.
If neither condition matches, the node has no children and is therefore labeled "Leaf".
Using DISTINCT is not strictly required for correctness, but it avoids redundant duplicate parent IDs.
Go Solution
For database problems, Go is generally represented as the SQL query string used in a submission wrapper.
package main
func treeNode() string {
return `
SELECT
id,
CASE
WHEN p_id IS NULL THEN 'Root'
WHEN id IN (
SELECT DISTINCT p_id
FROM Tree
WHERE p_id IS NOT NULL
) THEN 'Inner'
ELSE 'Leaf'
END AS type
FROM Tree
`
}
The Go version simply returns the SQL query as a raw string literal. Unlike algorithmic problems, there is no tree traversal or memory management required because the database engine performs the computation.
There are no Go-specific concerns such as slices, maps, integer overflow, or nil handling because the core logic is SQL-based.
Worked Examples
Example 1
Input table:
| id | p_id |
|---|---|
| 1 | NULL |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
First, gather all non-null parent IDs:
{1, 2}
Now classify each node.
| Node | p_id | Is Root? | In Parent Set? | Result |
|---|---|---|---|---|
| 1 | NULL | Yes | Yes | Root |
| 2 | 1 | No | Yes | Inner |
| 3 | 1 | No | No | Leaf |
| 4 | 2 | No | No | Leaf |
| 5 | 2 | No | No | Leaf |
Final output:
| id | type |
|---|---|
| 1 | Root |
| 2 | Inner |
| 3 | Leaf |
| 4 | Leaf |
| 5 | Leaf |
Example 2
Input table:
| id | p_id |
|---|---|
| 1 | NULL |
First, collect parent IDs:
{}
Now classify:
| Node | p_id | Is Root? | In Parent Set? | Result |
|---|---|---|---|---|
| 1 | NULL | Yes | No | Root |
Final output:
| id | type |
|---|---|
| 1 | Root |
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | Each node is processed once, and parent lookup is efficient |
| Space | O(n) | Parent IDs conceptually form a lookup set |
The dominant work comes from scanning the table and identifying parent IDs. In practice, database engines optimize the IN subquery efficiently, often using indexes or hash-based membership checks.
Test Cases
Since this is a SQL problem, test cases are best represented as input tables and expected outputs.
# Example 1
tree = [
(1, None),
(2, 1),
(3, 1),
(4, 2),
(5, 2)
]
expected = {
1: "Root",
2: "Inner",
3: "Leaf",
4: "Leaf",
5: "Leaf"
}
# Example 2, single node tree
tree = [
(1, None)
]
expected = {
1: "Root"
}
# Root with one child
tree = [
(1, None),
(2, 1)
]
expected = {
1: "Root",
2: "Leaf"
}
# Deep chain
tree = [
(1, None),
(2, 1),
(3, 2),
(4, 3)
]
expected = {
1: "Root",
2: "Inner",
3: "Inner",
4: "Leaf"
}
# Wide tree
tree = [
(1, None),
(2, 1),
(3, 1),
(4, 1),
(5, 1)
]
expected = {
1: "Root",
2: "Leaf",
3: "Leaf",
4: "Leaf",
5: "Leaf"
}
| Test | Why |
|---|---|
| Example 1 | Validates mixed node types |
| Example 2 | Tests single-node tree edge case |
| Root with one child | Ensures root classification overrides child existence |
| Deep chain | Verifies inner nodes in linear trees |
| Wide tree | Confirms multiple leaf detection |
Edge Cases
Single Node Tree
A tree with only one node is an important corner case. Technically, the node has no parent and no children, which could make classification ambiguous. The problem definition resolves this by prioritizing "Root". Since the implementation checks p_id IS NULL first, the node is correctly labeled "Root".
Root Node With Children
The root node can also have children. A naive implementation might mistakenly classify it as "Inner" because it appears in the parent set. This implementation avoids that bug by checking for root status first. Once p_id IS NULL is true, the node is immediately classified as "Root".
Nodes With No Children
Leaf nodes are identified indirectly, by exclusion. A node that is not the root and does not appear as a parent ID must be a leaf. This logic ensures correctness even when many nodes share the same parent or when the tree is highly unbalanced.