You are 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).
Example 1:
Input: root = [1,2,3,5,2,2,5], target = 2
Output: [1,2,3,5,null,null,5]Example 2:
Input: root = [3,null,3,3], target = 3
Output: []Explanation: The output is an empty tree after removing all the nodes with value 3.
Constraints:
1 <= number of nodes in the tree <= 30001 <= Node.val, target <= 1000Before attempting this problem, you should be comfortable with:
When we delete a leaf with the target value, its parent might become a new leaf. This means we need to process children before parents, which is exactly what postorder traversal does. By recursively processing left and right subtrees first, any newly exposed leaves are handled automatically when we return to the parent.
null, return null.root.left with the result.root.right with the result.null) and has the target value. If so, return null to delete it.# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def removeLeafNodes(self, root: Optional[TreeNode], target: int) -> Optional[TreeNode]:
if not root:
return None
root.left = self.removeLeafNodes(root.left, target)
root.right = self.removeLeafNodes(root.right, target)
if not root.left and not root.right and root.val == target:
return None
return rootWe can simulate postorder traversal using a stack and a set to track visited nodes. We also need to maintain parent pointers so that when we delete a leaf, we can update its parent's child reference. A node is processed only after both its children have been visited.
null.# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def removeLeafNodes(self, root: Optional[TreeNode], target: int) -> Optional[TreeNode]:
stack = [root]
visit = set()
parents = {root: None}
while stack:
node = stack.pop()
if not node.left and not node.right:
if node.val == target:
p = parents[node]
if not p:
return None
if p.left == node:
p.left = None
if p.right == node:
p.right = None
elif node not in visit:
visit.add(node)
stack.append(node)
if node.left:
stack.append(node.left)
parents[node.left] = node
if node.right:
stack.append(node.right)
parents[node.right] = node
return rootWe can optimize the iterative approach by using a standard postorder traversal pattern without maintaining a separate parent map. The stack itself naturally tracks the parent: after processing a node, the next item on the stack is its parent. We use a visited pointer to avoid reprocessing the right subtree.
visited pointer to track the last processed node.visited.# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def removeLeafNodes(self, root: Optional[TreeNode], target: int) -> Optional[TreeNode]:
if not root:
return None
stack = []
cur = root
visited = None
while stack or cur:
while cur:
stack.append(cur)
cur = cur.left
cur = stack[-1]
if cur.right and cur.right != visited:
cur = cur.right
continue
stack.pop()
if not cur.left and not cur.right and cur.val == target:
if not stack:
return None
parent = stack[-1]
if parent.left == cur:
parent.left = None
elif parent.right == cur:
parent.right = None
else:
visited = cur
cur = None
return rootDeleting leaves must be done bottom-up. If you check a node before processing its children (preorder), you miss newly created leaves when children are deleted.
# Wrong: preorder - checks before children are processed
if not root.left and not root.right and root.val == target:
return None
root.left = self.removeLeafNodes(root.left, target)
root.right = self.removeLeafNodes(root.right, target)
# Correct: postorder - process children first
root.left = self.removeLeafNodes(root.left, target)
root.right = self.removeLeafNodes(root.right, target)
if not root.left and not root.right and root.val == target:
return NoneA node should only be deleted if it is both a leaf (no children) AND has the target value. Missing either condition causes incorrect deletions.
# Wrong: only checks value, deletes non-leaves
if root.val == target:
return None
# Wrong: deletes all leaves regardless of value
if not root.left and not root.right:
return None
# Correct: must be leaf AND have target value
if not root.left and not root.right and root.val == target:
return None