Given the root
of a binary tree and an integer k
, you are asked to find the distance to the nearest leaf node from the node that has the value k
in the tree.
Here, the distance of a leaf to a node is defined as the number of edges on the path from the node to the nearest leaf.
Return the distance to the nearest leaf node from the node that has the value k
in the tree. If there is more than one node with the value k
, return the minimum of these distances. If the node with the value k
doesn't exist in the tree, return -1
.
Example 1:
Input: root = [1,2,3,null,null,4,5,null,null,6,7], k = 2 Output: 2 Explanation: The nearest leaf node to the node with value 2 is the node with value 6. The distance is 2.
Example 2:
Input: root = [1], k = 1 Output: 0 Explanation: The nearest leaf node to the node with value 1 is the node with value 1. The distance is 0.
Example 3:
Input: root = [1,2,3,null,null,4,5,null,null,6,7], k = 5 Output: 2 Explanation: The nearest leaf node to the node with value 5 is the node with value 6. The distance is 2.
Constraints:
[1, 1000]
.1 <= Node.val <= 1000
1 <= k <= 1000
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach to finding the closest leaf in a binary tree is like exploring every possible path from the target node. We will check the distance to every leaf node in the entire tree. Ultimately, we'll pick the closest one we found.
Here's how the algorithm would work step-by-step:
def find_closest_leaf_brute_force(root, target_node):
if not root:
return -1
closest_distance = float('inf')
def get_distance(node_a, node_b):
if not node_a or not node_b:
return float('inf')
# Simple helper function to calculate distance between two nodes
def find_path(start_node, end_node, current_path):
if not start_node:
return None
current_path.append(start_node)
if start_node == end_node:
return current_path
left_path = find_path(start_node.left, end_node, current_path[:])
if left_path:
return left_path
right_path = find_path(start_node.right, end_node, current_path[:])
if right_path:
return right_path
return None
path = find_path(node_a, node_b, [])
if path:
return len(path) - 1
else:
return float('inf')
def is_leaf(node):
return node and not node.left and not node.right
def traverse(current_node):
nonlocal closest_distance
if not current_node:
return
# Check if the current node is a leaf
if is_leaf(current_node):
# Calculate distance and update if smaller
distance = get_distance(target_node, current_node)
closest_distance = min(closest_distance, distance)
traverse(current_node.left)
traverse(current_node.right)
# Start traversal from the root to check every node
traverse(root)
return closest_distance
The most efficient way to find the closest leaf to a given node in a binary tree is to combine two search strategies. We'll explore upwards from the target node while simultaneously exploring downwards from each node we reach on the upward path. This lets us quickly find leaves both near and 'above' the target node.
Here's how the algorithm would work step-by-step:
def find_closest_leaf(root, target):
parent_map = {}
def populate_parent_map(node, parent):
if node:
parent_map[node] = parent
populate_parent_map(node.left, node)
populate_parent_map(node.right, node)
populate_parent_map(root, None)
target_node = find_target_node(root, target)
if not target_node:
return None
closest_distance = float('inf')
closest_leaf_node = None
visited = set()
queue = [(target_node, 0)]
visited.add(target_node)
while queue:
current_node, current_distance = queue.pop(0)
# Check if the current node is a leaf.
if not current_node.left and not current_node.right:
if current_distance < closest_distance:
closest_distance = current_distance
closest_leaf_node = current_node
# Explore downwards.
if current_node.left and current_node.left not in visited:
queue.append((current_node.left, current_distance + 1))
visited.add(current_node.left)
if current_node.right and current_node.right not in visited:
queue.append((current_node.right, current_distance + 1))
visited.add(current_node.right)
# Explore upwards towards the root.
parent = parent_map.get(current_node)
if parent and parent not in visited:
queue.append((parent, current_distance + 1))
visited.add(parent)
return closest_leaf_node.val
def find_target_node(root, target):
if not root:
return None
if root.val == target:
return root
left_search = find_target_node(root.left, target)
if left_search:
return left_search
return find_target_node(root.right, target)
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
Case | How to Handle |
---|---|
Root is null | Return null, as there are no nodes and thus no closest leaf. |
Target node is the root itself and the root is a leaf | Return the root itself immediately, as it's the closest leaf. |
Tree consists of a single node which is also the target | Return the single node itself as the closest leaf. |
Target node does not exist in the tree | Return null or throw an exception, indicating target node not found. |
Target node is very deep within a highly unbalanced tree | Ensure the algorithm (BFS or DFS) can efficiently traverse such trees without stack overflow or excessive time complexity. |
Multiple leaves are equidistant from the target node | Return any one of the closest leaves, as the problem only asks for 'a' closest leaf. |
Tree with only a single branch (essentially a linked list) | Algorithm should still correctly find the closest leaf, which will be the end of the single branch. |
Integer overflow during distance calculation if tree is extremely deep | Use appropriate data types (e.g., long) or carefully check for potential overflow conditions during distance calculations. |