Delete Node in a BST
Imagine managing a dynamic directory of contacts where you need to remove entries efficiently while maintaining sorted order for quick lookup.
Given the root of a binary search tree (BST) and a key, delete the node with the given key in the BST. Return the root node of the BST after deletion. The deletion must maintain the BST property.
The number of nodes in the tree is in the range [1, 10^5].Node values are unique.The key is guaranteed to be in the BST."root = [5,3,6,2,4,null,7], key = 3"[5,4,6,2,null,null,7]Node 3 has two children. Replace it with its inorder successor 4, then delete node 4.
- Deleting a leaf node → simply remove it
- Deleting a node with only one child → replace node with child
- Deleting the root node → tree root changes
- Deleting a node not present → tree remains unchanged
BST property breaks or incorrect node deleted
✅ Always replace with inorder successor or predecessor and delete that node recursively
Deleted node remains linked, causing incorrect tree structure
✅ Track parent node and update its left or right pointer accordingly
Tree root becomes null or incorrect node
✅ Check if parent is null and return child as new root
Null pointer exceptions or infinite loops
✅ Add base case checks for null root and return original tree if key not found
Intuition
Recursively search for the node to delete. Once found, handle three cases: leaf node, node with one child, and node with two children by replacing with inorder successor.
Algorithm
- If root is null, return null.
- If key is less than root's value, recurse on left subtree.
- If key is greater than root's value, recurse on right subtree.
- If key equals root's value, handle deletion:
- - If node is leaf, return null.
- - If node has one child, return that child.
- - If node has two children, find inorder successor, replace node's value, and delete successor recursively.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def deleteNode(root, key):
if not root:
return None
if key < root.val:
root.left = deleteNode(root.left, key)
elif key > root.val:
root.right = deleteNode(root.right, key)
else:
if not root.left:
return root.right
elif not root.right:
return root.left
else:
successor = root.right
while successor.left:
successor = successor.left
root.val = successor.val
root.right = deleteNode(root.right, successor.val)
return root
# Example usage:
# Construct BST and call deleteNode(root, key)if not root:Base case: if tree/subtree is empty, nothing to deleteif key < root.val:Search left subtree if key is smallerelif key > root.val:Search right subtree if key is largerelse:Found node to deleteif not root.left:If no left child, replace node with right childelif not root.right:If no right child, replace node with left childsuccessor = root.rightFind inorder successor in right subtreewhile successor.left:Go as left as possible to find smallest noderoot.val = successor.valReplace current node's value with successor's valueroot.right = deleteNode(root.right, successor.val)Delete successor node recursivelyclass TreeNode {
int val;
TreeNode left, right;
TreeNode(int x) { val = x; }
}
public class 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;
else if (root.right == null) return root.left;
else {
TreeNode successor = root.right;
while (successor.left != null) successor = successor.left;
root.val = successor.val;
root.right = deleteNode(root.right, successor.val);
}
}
return root;
}
// Example main method to test
public static void main(String[] args) {
// Build BST and call deleteNode
}
}if (root == null) return null;Base case: empty subtreeif (key < root.val)Traverse left subtree if key smallerelse if (key > root.val)Traverse right subtree if key largerelse {Found node to deleteif (root.left == null) return root.right;No left child, replace with rightelse if (root.right == null) return root.left;No right child, replace with leftTreeNode successor = root.right;Find inorder successorwhile (successor.left != null) successor = successor.left;Go left to find smallest noderoot.val = successor.val;Replace value with successor'sroot.right = deleteNode(root.right, successor.val);Delete successor recursively#include <iostream>
using namespace std;
struct TreeNode {
int val;
TreeNode *left, *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
TreeNode* deleteNode(TreeNode* root, int key) {
if (!root) 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) return root->right;
else if (!root->right) return root->left;
else {
TreeNode* successor = root->right;
while (successor->left) successor = successor->left;
root->val = successor->val;
root->right = deleteNode(root->right, successor->val);
}
}
return root;
}
// Example usage in main
int main() {
// Build BST and call deleteNode
return 0;
}if (!root) return NULL;Base case: empty subtreeif (key < root->val)Traverse left subtree if key smallerelse if (key > root->val)Traverse right subtree if key largerelse {Found node to deleteif (!root->left) return root->right;No left child, replace with rightelse if (!root->right) return root->left;No right child, replace with leftTreeNode* successor = root->right;Find inorder successorwhile (successor->left) successor = successor->left;Go left to find smallest noderoot->val = successor->val;Replace value with successor'sroot->right = deleteNode(root->right, successor->val);Delete successor recursivelyfunction TreeNode(val, left=null, right=null) {
this.val = val;
this.left = left;
this.right = right;
}
function deleteNode(root, key) {
if (!root) 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) return root.right;
else if (!root.right) return root.left;
else {
let successor = root.right;
while (successor.left) successor = successor.left;
root.val = successor.val;
root.right = deleteNode(root.right, successor.val);
}
}
return root;
}
// Example usage:
// let root = new TreeNode(...);
// console.log(deleteNode(root, key));if (!root) return null;Base case: empty subtreeif (key < root.val)Traverse left subtree if key smallerelse if (key > root.val)Traverse right subtree if key largerelse {Found node to deleteif (!root.left) return root.right;No left child, replace with rightelse if (!root.right) return root.left;No right child, replace with leftlet successor = root.right;Find inorder successorwhile (successor.left) successor = successor.left;Go left to find smallest noderoot.val = successor.val;Replace value with successor'sroot.right = deleteNode(root.right, successor.val);Delete successor recursivelyO(h) where h is the height of the BSTO(h) due to recursion stackWe traverse down the tree once to find the node, which takes O(h). Deletion and successor search also take O(h) in worst case.
This approach is efficient for balanced BSTs and is the standard recursive solution interviewers expect.
Intuition
Use a loop to find the node and its parent. Then handle deletion cases by adjusting pointers iteratively.
Algorithm
- Initialize parent and current pointers starting at root.
- Iteratively search for the node with the key, updating parent.
- If node not found, return original root.
- If node has two children, find inorder successor and its parent.
- Replace node's value with successor's value.
- Delete successor node by adjusting parent's child pointer.
- If node has one or zero children, replace node with child directly.
- Return updated root.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def deleteNode(root, key):
parent = None
curr = root
# Find node to delete
while curr and curr.val != key:
parent = curr
if key < curr.val:
curr = curr.left
else:
curr = curr.right
if not curr:
return root
# Node with two children
if curr.left and curr.right:
succ_parent = curr
succ = curr.right
while succ.left:
succ_parent = succ
succ = succ.left
curr.val = succ.val
curr = succ
parent = succ_parent
# Node with zero or one child
child = curr.left if curr.left else curr.right
if not parent:
return child
if parent.left == curr:
parent.left = child
else:
parent.right = child
return root
# Example usage:
# Construct BST and call deleteNode(root, key)parent = NoneInitialize parent pointer to track node's parentwhile curr and curr.val != key:Iteratively search for node with keyif not curr:If node not found, return original treeif curr.left and curr.right:If node has two children, find inorder successorwhile succ.left:Find leftmost node in right subtreecurr.val = succ.valReplace node's value with successor'schild = curr.left if curr.left else curr.rightIdentify child to replace nodeif not parent:If deleting root, return child as new rootif parent.left == curr:Update parent's left or right pointer accordinglyclass TreeNode {
int val;
TreeNode left, right;
TreeNode(int x) { val = x; }
}
public class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
TreeNode parent = null, curr = root;
while (curr != null && curr.val != key) {
parent = curr;
if (key < curr.val) curr = curr.left;
else curr = curr.right;
}
if (curr == null) return root;
if (curr.left != null && curr.right != null) {
TreeNode succParent = curr;
TreeNode succ = curr.right;
while (succ.left != null) {
succParent = succ;
succ = succ.left;
}
curr.val = succ.val;
curr = succ;
parent = succParent;
}
TreeNode child = (curr.left != null) ? curr.left : curr.right;
if (parent == null) return child;
if (parent.left == curr) parent.left = child;
else parent.right = child;
return root;
}
// main method omitted for brevity
}TreeNode parent = null, curr = root;Initialize pointers to track current node and its parentwhile (curr != null && curr.val != key)Iteratively find node to deleteif (curr == null) return root;If node not found, return original treeif (curr.left != null && curr.right != null)If node has two children, find inorder successorwhile (succ.left != null)Find leftmost node in right subtreecurr.val = succ.val;Replace node's value with successor'sTreeNode child = (curr.left != null) ? curr.left : curr.right;Identify child to replace nodeif (parent == null) return child;If deleting root, return child as new rootif (parent.left == curr) parent.left = child;Update parent's pointer to bypass deleted node#include <iostream>
using namespace std;
struct TreeNode {
int val;
TreeNode *left, *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
TreeNode* deleteNode(TreeNode* root, int key) {
TreeNode* parent = NULL;
TreeNode* curr = root;
while (curr && curr->val != key) {
parent = curr;
if (key < curr->val) curr = curr->left;
else curr = curr->right;
}
if (!curr) return root;
if (curr->left && curr->right) {
TreeNode* succParent = curr;
TreeNode* succ = curr->right;
while (succ->left) {
succParent = succ;
succ = succ->left;
}
curr->val = succ->val;
curr = succ;
parent = succParent;
}
TreeNode* child = curr->left ? curr->left : curr->right;
if (!parent) return child;
if (parent->left == curr) parent->left = child;
else parent->right = child;
return root;
}
int main() {
// Build BST and call deleteNode
return 0;
}TreeNode* parent = NULL;Track parent node for re-linkingwhile (curr && curr->val != key)Iteratively find node to deleteif (!curr) return root;If node not found, return original treeif (curr->left && curr->right)If node has two children, find inorder successorwhile (succ->left)Find leftmost node in right subtreecurr->val = succ->val;Replace node's value with successor'sTreeNode* child = curr->left ? curr->left : curr->right;Identify child to replace nodeif (!parent) return child;If deleting root, return child as new rootif (parent->left == curr) parent->left = child;Update parent's pointer to bypass deleted nodefunction TreeNode(val, left=null, right=null) {
this.val = val;
this.left = left;
this.right = right;
}
function deleteNode(root, key) {
let parent = null, curr = root;
while (curr && curr.val !== key) {
parent = curr;
if (key < curr.val) curr = curr.left;
else curr = curr.right;
}
if (!curr) return root;
if (curr.left && curr.right) {
let succParent = curr;
let succ = curr.right;
while (succ.left) {
succParent = succ;
succ = succ.left;
}
curr.val = succ.val;
curr = succ;
parent = succParent;
}
let child = curr.left ? curr.left : curr.right;
if (!parent) return child;
if (parent.left === curr) parent.left = child;
else parent.right = child;
return root;
}
// Example usage:
// let root = new TreeNode(...);
// console.log(deleteNode(root, key));let parent = null, curr = root;Initialize pointers to track current node and parentwhile (curr && curr.val !== key)Iteratively find node to deleteif (!curr) return root;If node not found, return original treeif (curr.left && curr.right)If node has two children, find inorder successorwhile (succ.left)Find leftmost node in right subtreecurr.val = succ.val;Replace node's value with successor'slet child = curr.left ? curr.left : curr.right;Identify child to replace nodeif (!parent) return child;If deleting root, return child as new rootif (parent.left === curr) parent.left = child;Update parent's pointer to bypass deleted nodeO(h) where h is the height of the BSTO(1) iterative approach uses constant extra spaceWe traverse the tree once to find the node and possibly its successor, both O(h). No recursion stack is used.
This approach is preferred when recursion depth is a concern and demonstrates pointer manipulation skills.
Intuition
Use recursion for deletion and a helper function to find the inorder successor, making the main function cleaner and easier to understand.
Algorithm
- If root is null, return null.
- Recursively search left or right subtree based on key.
- If node to delete found:
- - If no left child, return right child.
- - If no right child, return left child.
- - Otherwise, find inorder successor using helper, replace node's value, and delete successor recursively.
- Return root.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def findSuccessor(node):
curr = node.right
while curr.left:
curr = curr.left
return curr
def deleteNode(root, key):
if not root:
return None
if key < root.val:
root.left = deleteNode(root.left, key)
elif key > root.val:
root.right = deleteNode(root.right, key)
else:
if not root.left:
return root.right
elif not root.right:
return root.left
else:
successor = findSuccessor(root)
root.val = successor.val
root.right = deleteNode(root.right, successor.val)
return root
# Example usage:
# Construct BST and call deleteNode(root, key)def findSuccessor(node):Helper function to find inorder successorcurr = node.rightStart from right child to find successorwhile curr.left:Go left as far as possibleif key < root.val:Recurse left if key smallerelif key > root.val:Recurse right if key largerif not root.left:No left child, replace with rightelif not root.right:No right child, replace with leftsuccessor = findSuccessor(root)Use helper to find successorroot.right = deleteNode(root.right, successor.val)Delete successor recursivelyclass TreeNode {
int val;
TreeNode left, right;
TreeNode(int x) { val = x; }
}
public class Solution {
private TreeNode findSuccessor(TreeNode node) {
TreeNode curr = node.right;
while (curr.left != null) curr = curr.left;
return curr;
}
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;
else if (root.right == null) return root.left;
else {
TreeNode successor = findSuccessor(root);
root.val = successor.val;
root.right = deleteNode(root.right, successor.val);
}
}
return root;
}
// main method omitted for brevity
}private TreeNode findSuccessor(TreeNode node)Helper method to find inorder successorTreeNode curr = node.right;Start from right childwhile (curr.left != null)Go left as far as possibleif (key < root.val)Recurse left if key smallerelse if (key > root.val)Recurse right if key largerif (root.left == null) return root.right;No left child, replace with rightelse if (root.right == null) return root.left;No right child, replace with leftTreeNode successor = findSuccessor(root);Find successor using helperroot.right = deleteNode(root.right, successor.val);Delete successor recursively#include <iostream>
using namespace std;
struct TreeNode {
int val;
TreeNode *left, *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
TreeNode* findSuccessor(TreeNode* node) {
TreeNode* curr = node->right;
while (curr->left) curr = curr->left;
return curr;
}
TreeNode* deleteNode(TreeNode* root, int key) {
if (!root) 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) return root->right;
else if (!root->right) return root->left;
else {
TreeNode* successor = findSuccessor(root);
root->val = successor->val;
root->right = deleteNode(root->right, successor->val);
}
}
return root;
}
int main() {
// Build BST and call deleteNode
return 0;
}TreeNode* findSuccessor(TreeNode* node)Helper function to find inorder successorTreeNode* curr = node->right;Start from right childwhile (curr->left) curr = curr->left;Go left as far as possibleif (key < root->val) root->left = deleteNode(root->left, key);Recurse left if key smallerelse if (key > root->val) root->right = deleteNode(root->right, key);Recurse right if key largerif (!root->left) return root->right;No left child, replace with rightelse if (!root->right) return root->left;No right child, replace with leftTreeNode* successor = findSuccessor(root);Find successor using helperroot->right = deleteNode(root->right, successor->val);Delete successor recursivelyfunction TreeNode(val, left=null, right=null) {
this.val = val;
this.left = left;
this.right = right;
}
function findSuccessor(node) {
let curr = node.right;
while (curr.left) curr = curr.left;
return curr;
}
function deleteNode(root, key) {
if (!root) 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) return root.right;
else if (!root.right) return root.left;
else {
let successor = findSuccessor(root);
root.val = successor.val;
root.right = deleteNode(root.right, successor.val);
}
}
return root;
}
// Example usage:
// let root = new TreeNode(...);
// console.log(deleteNode(root, key));function findSuccessor(node)Helper function to find inorder successorlet curr = node.right;Start from right childwhile (curr.left) curr = curr.left;Go left as far as possibleif (key < root.val) root.left = deleteNode(root.left, key);Recurse left if key smallerelse if (key > root.val) root.right = deleteNode(root.right, key);Recurse right if key largerif (!root.left) return root.right;No left child, replace with rightelse if (!root.right) return root.left;No right child, replace with leftlet successor = findSuccessor(root);Find successor using helperroot.right = deleteNode(root.right, successor.val);Delete successor recursivelyO(h) where h is the height of the BSTO(h) due to recursion stackSimilar to approach 1, but code is cleaner due to helper function separation.
This is a clean, maintainable recursive solution preferred in many interviews.
| Approach | Time | Space | Stack Risk | Reconstruct | Use In Interview |
|---|---|---|---|---|---|
| 1. Brute Force (Recursive) | O(h) | O(h) recursion stack | Yes for very deep trees | N/A | Standard solution to implement and explain |
| 2. Iterative with Parent Pointers | O(h) | O(1) | No | N/A | Good to mention or implement if recursion is a concern |
| 3. Recursive with Helper Function | O(h) | O(h) | Yes | N/A | Preferred for clean, maintainable code |
How to Present
Clarify the problem and constraints with the interviewer.Describe the brute force recursive approach and its cases.Discuss iterative approach to avoid recursion stack.Explain helper function usage for cleaner code.Write code carefully handling all cases.Test with edge cases and explain time/space complexity.
Time Allocation
What the Interviewer Tests
Interviewer tests your understanding of BST properties, handling of deletion cases, recursion or iteration skills, and code clarity.
Common Follow-ups
- How to handle duplicate keys? → BST usually has unique keys; duplicates require design decisions.
- Can you implement iterative deletion without parent pointers? → More complex, but possible with stack.
When to Use
1) Problem involves BST node removal, 2) Must maintain BST property, 3) Need to handle three deletion cases, 4) Inorder successor/predecessor needed.
