Leetcode 742. Closest Leaf in a Binary Tree

Problem Explanation

Given a binary tree where each node has a unique value, the goal is to find the value of the nearest leaf node to a target node k.

Nearest is defined by the least number of edges travelled to reach a leaf node. A node is categorized as leaf only if it has no children.

For example, let's consider the binary tree in the form of a list [1, 3, 2] where k is 1. The binary tree can be showed as:

1
2
3  1
4 / \
53   2

In this tree, the nearest leaf node to the target k(1) is either 2 or 3.

Walk through an Example

Given a binary tree [1, 2, 3, 4, null, null, null, 5, null, 6] and k as 2, let's walk through how to find the nearest leaf node.

The binary tree can be showed as:

1
2
3     1
4    / \
5   2   3
6  /
7 4
8/
95
10/
116

The nearest leaf node to k (2) is 3.

Solution Approach

The solution uses depth first search (DFS) methodology to solve the problem. This solution makes use of an unordered_map in C++ (Dictionary in Python, Map Object in Java and JavaScript) to store the shortest distance to the target node k from all nodes in the tree.

Initially, all distances are calculated from the target node k to every other node in the binary tree and stored in a Map object. Then, the algorithm performs DFS on the binary tree again but this time trying to find the nearest leaf node by comparing distances from the target node k.

The minimum distance to leaf node is updated whenever a smaller distance is found.

The approach can be grouped as follows:

  1. Create a Map Object to store distance from all nodes to the target node k.
  2. Calculate the distance to target node from all nodes and store them in the Map Object.
  3. Initialize a variables to keep track of the minimum distance and the value of the nearest leaf node.
  4. DFS on the binary tree, compare the distances from target k node and update the minimum distance and value of the nearest leaf node whenever a smaller distance is found.

Python Solution

1
2python
3class Solution:
4    def findClosestLeaf(self, root, k):
5        G = collections.defaultdict(list)
6        def dfs(node, par = None):
7            if node:
8                G[node].append(par)
9                G[par].append(node)
10                dfs(node.left, node)
11                dfs(node.right, node)
12
13        dfs(root)
14        block, q = {k}, [k]
15        while q:
16            node = q.pop()
17            if node:
18                if len(G[node]) <= 1:
19                    return node.val
20                for nx in G[node]:
21                    if nx not in block:
22                        block.add(nx)
23                        q.append(nx)

Java Solution

1
2java
3class Solution {
4    public int findClosestLeaf(TreeNode root, int k) {
5        // dfs to find the closest leaf node
6        dfs(root, k);
7        return closestLeaf(root);
8    }
9
10    private int kNodeLevel = -1;
11
12    // return the level of the k node, otherwise -1
13    private int dfs(TreeNode root, int k){
14        if(root == null){
15            return -1;
16        }else if(root.val == k){
17            kNodeLevel = 0;
18            return 0;
19        }else{
20            int left = dfs(root.left, k), 
21                right = dfs(root.right, k);
22
23            if(right >= 0){
24                kNodeLevel = ++right;
25                return right;
26            }
27
28            if(left >= 0){
29                kNodeLevel = ++left;
30                return left;
31            }
32
33            return -1;
34        }
35    }
36
37    private int closestLeafLevel = Integer.MAX_VALUE, ans = 0;
38
39    private int closestLeaf(TreeNode root){
40        if(root == null){
41            return Integer.MAX_VALUE;
42        }else if(root.left == null && root.right == null){
43            if(kNodeLevel >= 0 && kNodeLevel < closestLeafLevel){
44                closestLeafLevel = kNodeLevel;
45                ans = root.val;
46            }
47            return 1;
48        }else{
49            int left = closestLeaf(root.left), 
50                right = closestLeaf(root.right),
51                currentLevel = Math.min(left, right) + 1;
52            if(kNodeLevel == -1){
53                return currentLevel;
54            }else{
55                if(currentLevel == kNodeLevel + 1){
56                    kNodeLevel++;
57                }else{
58                    kNodeLevel = -1;
59                }
60                return currentLevel;
61            }
62        }
63    }
64}

JavaScript Solution

1
2javascript
3var findClosestLeaf = function(root, k) {
4    let target;
5        const graph = new Map();
6        const queue = [root];
7        while(queue.length) {
8            const node = queue.shift();
9            if(node.left) {
10                graph.set(node, (graph.get(node) || new Set()).add(node.left));
11                graph.set(node.left, (graph.get(node.left) || new Set()).add(node));
12                queue.push(node.left);
13            }
14            if(node.right) {
15                graph.set(node, (graph.get(node) || new Set()).add(node.right));
16                graph.set(node.right, (graph.get(node.right) || new Set()).add(node));
17                queue.push(node.right);
18            }
19            if(node.val == k) target = node;
20        }
21        queue.push(target);
22        const visited = new Set(queue);
23        while(queue.length) {
24            const node = queue.shift();
25            if(graph.get(node).size == 1) return node.val;
26            for(let neighbor of graph.get(node)) {
27                if(!visited.has(neighbor)) {
28                    visited.add(neighbor);
29                    queue.push(neighbor);
30                }
31            }
32        }
33    };

C++ Solution

1
2C++
3class Solution {
4public:
5    int findClosestLeaf(TreeNode* root, int k) {
6        unordered_map<int, vector<int>> graph;
7        TreeNode* start = dfs(root, k, graph);
8        queue<TreeNode*> q({start});
9        unordered_set<TreeNode*> vis({start});
10        while (!q.empty()) {
11            auto t = q.front(); q.pop();
12            if (!t->left && !t->right) return t->val;
13            for (int i: graph[t->val]) {
14                TreeNode* y = new TreeNode(i);
15                if (!vis.count(y)) {
16                    vis.insert(y);
17                    q.push(y);
18                }
19            }
20        }
21        return 0;
22    }
23    TreeNode* dfs(TreeNode* node, int k, unordered_map<int, vector<int>>& graph) {
24        if (!node) return NULL;
25        if (node->val == k) start = node;
26        if (node->left) {
27            graph[node->val].push_back(node->left->val);
28            graph[node->left->val].push_back(node->val);
29            dfs(node->left, k, graph);
30        }
31        if (node->right) {
32            graph[node->val].push_back(node->right->val);
33            graph[node->right->val].push_back(node->val);
34            dfs(node->right, k, graph);
35        }
36        return start;
37    }
38
39private:
40    TreeNode* start;
41};

C# Solution

1
2csharp
3public class Solution {
4    public int FindClosestLeaf(TreeNode root, int k) {
5        Dictionary<int, List<int>> graph = new Dictionary<int, List<int>>();
6        int rootVal = BuildGraph(graph, root, k);
7        HashSet<int> visited = new HashSet<int>();
8        Queue<int> queue = new Queue<int>();
9        queue.Enqueue(rootVal);
10        visited.Add(rootVal);
11        while(queue.Count > 0){
12            int curr = queue.Dequeue();
13            List<int> currAdj = graph[curr];
14            if( currAdj.Count == 1 && curr != rootVal)
15                return curr;
16            foreach(int child in currAdj){
17                if(!visited.Contains(child)){
18                    visited.Add(child);
19                    queue.Enqueue(child);
20                }
21            }
22        }
23        return -1;
24    }
25    
26    public int BuildGraph(Dictionary<int, List<int>> graph, TreeNode root, int k){
27        if(root == null)
28            return -1;
29        else if(root.left == null && root.right == null ){
30            graph[root.val] = new List<int>();
31            return (root.val == k) ? root.val : -1;
32        }
33        else{
34            if(!graph.ContainsKey(root.val))
35                graph[root.val] = new List<int>();
36            if(root.left != null){
37                graph[root.val].Add(root.left.val);
38                if(!graph.ContainsKey(root.left.val))
39                    graph[root.left.val] = new List<int>();
40                graph[root.left.val].Add(root.val);
41                int left = BuildGraph(graph, root.left, k);
42                if(left != -1)
43                    return left;
44            }
45            if(root.right != null){
46                graph[root.val].Add(root.right.val);
47                if(!graph.ContainsKey(root.right.val))
48                    graph[root.right.val] = new List<int>();
49                graph[root.right.val].Add(root.val);
50                int right = BuildGraph(graph, root.right, k);
51                if(right != -1)
52                    return right;
53            }
54            return (root.val == k) ? root.val : -1;
55        }        
56    }
57}

In conclusion, this problem is solved by following a depth-first search approach. The key to solving this problem is to get the distances from all nodes to target node k. After having the dictionary ready with all the distances, the problem becomes a traversal problem to find the nearest leaf node by comparing the distances from the target k node.The above-mentioned solutions aim to find the shortest distance from the target node to a leaf node in the Binary Tree. This can be applied in various scenarios in real life where we need to find the shortest path from one point to another. For instance, it can be used in calculating the shortest routes in GPS navigation systems. It can also be used in optimizing resource allocation and data processing in computer networks.

The Python solution uses a Dictionary to store distances from all nodes to the target node k, performs DFS, and updates the value of the closest leaf node whenever a smaller distance is found.

The Java solution mainly focuses on two methods, DFS and closestLeaf. DFS is used to find the level of node k and closestLeaf is used to get the value of the closest leaf node. Moreover, it uses recursive calls to visit all nodes in the binary tree.

The JavaScript solution uses a Map object to store each node and its corresponding neighbor nodes in the binary tree. Similar to the Python solution, BFS is performed, but with the aim to find the nearest leaf node by comparing distances.

The C++ solution uses an unordered_map to graph all nodes connecting to its children and parents and then performs BFS to find the nearest leaf node. BFS is used instead of DFS because BFS is better suited to find the shortest path in a graph which represents the simplest & optimal solution in this case.

The C# solution is similar to the C++ solution, where a Dictionary is used to store and graph the nodes. After getting all the nodes graphed, it then performs BFS looking for the nearest leaf node.

By understanding these solutions, you can have better problem-solving skills and improve your coding skills. Even though these solutions are written in different programming languages, the core logic and principle are the same. Remember that having a good understanding of tree-based data structures and algorithms like DFS and BFS is very essential for you to solve this kind of problem.

Also, please note that the given solutions assume that a valid binary tree and a target node k always exist. In a real project, error checking and exception handling are necessary for covering edge cases, such as an empty tree, null nodes, or target k not existing in the tree.


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫