Given a binary tree root
and an integer target
, delete all the leaf nodes with value target
.
Note that once you delete a leaf node with value target
, if its parent node becomes a leaf node and has the value target
, it should also be deleted (you need to continue doing that until you cannot).
For example:
Consider the following binary tree:
1
/ \
2 3
/ \ / \
2 4 2 2
If target = 2
, the algorithm should proceed as follows:
1
/ \
_ 3
/ \ / \
_ 4 _ _
1
\
3
/
4
Consider the following binary tree:
1
/ \
3 3
/ \ / \
3 2 _ _
If target = 3
, the algorithm should return:
1
/ \
3 _
/
2
Write a function that takes the root of a binary tree and a target value as input and returns the modified binary tree after removing all leaf nodes with the specified target value, propagating the deletion upwards as needed.
Constraints:
[1, 3000]
.1 <= Node.val, target <= 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 method attacks this problem by repeatedly checking and modifying the tree until no more changes can be made. We look for leaves with the target value and remove them. This process is repeated until there are no more leaves with that value left in the tree.
Here's how the algorithm would work step-by-step:
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def delete_leaves_brute_force(root, target):
if not root:
return None
while True:
root, deleted_nodes = delete_leaves_once(root, target)
# If we didn't delete any nodes, we're done
if not deleted_nodes:
break
return root
def delete_leaves_once(root, target):
deleted_nodes = False
if not root:
return None, deleted_nodes
root.left, left_deleted = delete_leaves_once(root.left, target)
root.right, right_deleted = delete_leaves_once(root.right, target)
# Identify leaf nodes with the target value
if root.left is None and root.right is None and root.val == target:
return None, True
if left_deleted or right_deleted:
deleted_nodes = True
return root, deleted_nodes
The trick is to work from the bottom up. If we remove leaf nodes first, it simplifies the tree structure, making the overall task easier. We repeatedly check for and remove leaf nodes with the target value until no more can be removed.
Here's how the algorithm would work step-by-step:
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def delete_leaves(root, target):
def remove_leaves(node, target_value):
if not node:
return None
node.left = remove_leaves(node.left, target_value)
node.right = remove_leaves(node.right, target_value)
# Check if the current node is a leaf and has the target value.
if not node.left and not node.right and node.val == target_value:
return None
return node
# Keep removing leaves until no more can be removed.
while True:
original_root = root
root = remove_leaves(root, target)
# Check if the tree structure changed after removing leaves.
if root == original_root:
break
return root
Case | How to Handle |
---|---|
Null root node | Return null immediately as there's nothing to process. |
Tree with only a root node, and its value equals the target | Return null as the entire tree is now deleted. |
All leaf nodes have the target value | Repeated deletion will eventually eliminate the entire tree if interior nodes become leaves with the target value. |
Tree with many nodes having the target value concentrated in a single subtree | The recursive calls handle subtree deletions effectively, ensuring correct pruning. |
Deeply unbalanced tree to test recursion depth | Ensure the programming language's stack is large enough to avoid stack overflow errors, or convert to iterative approach if necessary. |
Tree with no leaf nodes having the target value | The function should complete normally, leaving the tree unmodified. |
The target value is the same as some, but not all, interior node values | Only leaf nodes matching the target value should be deleted, ensuring interior nodes are preserved unless they become leaves matching the target. |
Memory constraints with a very large tree | Iterative solutions might be more memory efficient than recursive ones for extremely large trees. |