Delete Node in a BST
The drill: Remove one value from a BST and hand back a tree that is still a valid BST — the tricky part is only the node with two children, since either neighbor can legally take its place.
A binary search tree and a key arrive together, and the task is to remove the node holding that key — if it exists — while the tree that remains still obeys BST ordering.
Removing a leaf or a node with a single child is straightforward: it simply gets spliced out. A node with two children is the interesting case, since either its inorder predecessor or its inorder successor can legally take its place without breaking the ordering.
If the key isn't present in the tree at all, the tree is handed back completely unchanged — there's nothing to remove.
- the key may or may not be present in the tree
- the tree can hold anywhere from zero to a few thousand nodes
- all values in the tree are unique and follow standard BST ordering
- either valid neighbor may replace a two-child node's spot
HINT 1 THE NUDGE
A leaf or a one-child node is easy: splice it out and reattach its single subtree. What breaks that trick when there are two children?
HINT 2 THE STRUCTURE
You need a replacement value that keeps the ordering intact — one that sits immediately next to the deleted value in sorted order. Where does that value live structurally?
HINT 3 ONE STEP FROM THE ANSWER
The inorder successor is the leftmost node of the right subtree. Copy its value into the node being deleted, then delete that successor from the right subtree instead — a smaller, solvable version of the same problem.
Delete key 3. It has two children, so instead of splicing it out we borrow its inorder successor's value.
class Solution:
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
if not root:
return None
if key < root.val:
root.left = self.deleteNode(root.left, key)
elif key > root.val:
root.right = self.deleteNode(root.right, key)
else:
if not root.left:
return root.right
if not root.right:
return root.left
succ = root.right
while succ.left: # leftmost of the right subtree
succ = succ.left
root.val = succ.val
root.right = self.deleteNode(root.right, succ.val)
return rootclass Solution:
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
if not root:
return None
if root.val == key:
if not root.left:
return root.right
if not root.right:
return root.left
succ = root.right
while succ.left:
succ = succ.left
root.val = succ.val
root.right = self.deleteNode(root.right, succ.val)
return root
# ignore the BST ordering — walk into both children regardless
root.left = self.deleteNode(root.left, key)
root.right = self.deleteNode(root.right, key)
return rootclass Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) {
return null;
}
if (key < root.val) {
root.left = deleteNode(root.left, key);
} else if (key > root.val) {
root.right = deleteNode(root.right, key);
} else {
if (root.left == null) {
return root.right;
}
if (root.right == null) {
return root.left;
}
TreeNode succ = root.right;
while (succ.left != null) {
succ = succ.left;
}
root.val = succ.val;
root.right = deleteNode(root.right, succ.val);
}
return root;
}
}class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) {
return null;
}
if (root.val == key) {
if (root.left == null) {
return root.right;
}
if (root.right == null) {
return root.left;
}
TreeNode succ = root.right;
while (succ.left != null) {
succ = succ.left;
}
root.val = succ.val;
root.right = deleteNode(root.right, succ.val);
return root;
}
// ignore the BST ordering — walk into both children regardless
root.left = deleteNode(root.left, key);
root.right = deleteNode(root.right, key);
return root;
}
}✓ CHIP-TIMED — ALL 4 SOLUTIONS RAN GREEN AGAINST SELF-AUTHORED CASES IN CI · JDK 21 · CPYTHON 3.12 · NOTHING PUBLISHES RED