Delete Node in a BST
Link
Description
Given a root node reference of a BST and a key, delete the node with the given key in the BST. Return the root node reference (possibly updated) of the BST.
Basically, the deletion can be divided into two stages:
- Search for a node to remove.
- If the node is found, delete the node.
Example 1:
- Input:
root = [5,3,6,2,4,null,7], key = 3
- Output:
[5,4,6,2,null,null,7]
- Explanation:
| Given key to delete is 3. So we find the node with value 3 and delete it.
One valid answer is [5,4,6,2,null,null,7], shown in the above BST.
Please notice that another valid answer is [5,2,6,null,4,null,7] and it's also accepted.
|
Example 2:
- Input:
root = [5,3,6,2,4,null,7], key = 0
- Output:
[5,3,6,2,4,null,7]
- Explanation:
The tree does not contain a node with value = 0.
Example 3:
- Input:
root = [], key = 0
- Output:
[]
Solution
Way 1
| /**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (!root) return nullptr;
if (root->val == key) {
if (!root->left && !root->right) {
delete root;
return nullptr;
} else if (!root->left) {
auto res = root->right;
delete root;
return res;
} else if (!root->right) {
auto res = root->left;
delete root;
return res;
} else { // root->left != nullptr && root->right != nullptr
auto curr = root->right;
while (curr->left) {
curr = curr->left;
}
curr->left = root->left;
auto temp = root;
root = root->right;
delete temp;
return root;
}
}
if (root->val > key) root->left = deleteNode(root->left, key);
if (root->val < key) root->right = deleteNode(root->right, key);
return root;
}
};
|
Way 2
| class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (!root) return nullptr;
if (root->val > key) {
root->left = deleteNode(root->left, key);
} else if (root->val < key) {
root->right = deleteNode(root->right, key);
} else if (!root->left) {
root = root->right;
} else if (!root->right) {
root = root->left;
} else {
auto successor = root->right;
while (successor->left) {
successor = successor->left;
}
root->val = successor->val;
root->right = deleteNode(root->right, successor->val);
}
return root;
}
};
|
Code without memory leaks:
| class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
// Base case: If the root is null, the tree does not contain the key.
if (!root) return nullptr;
// If the key to be deleted is smaller than the root's key,
// then it lies in the left subtree.
if (root->val > key) {
root->left = deleteNode(root->left, key);
}
// If the key to be deleted is greater than the root's key,
// then it lies in the right subtree.
else if (root->val < key) {
root->right = deleteNode(root->right, key);
}
// If the key is the same as the root's key, then this is the node
// to be deleted.
else {
// Node with only one child or no child.
if (!root->left) {
TreeNode* temp = root->right;
delete root; // Prevent memory leak by deallocating memory of the node to be deleted.
return temp;
} else if (!root->right) {
TreeNode* temp = root->left;
delete root; // Prevent memory leak by deallocating memory of the node to be deleted.
return temp;
}
// Node with two children: Get the inorder successor (smallest
// in the right subtree).
TreeNode* successor = findMin(root->right);
// Copy the inorder successor's content to this node.
root->val = successor->val;
// Delete the inorder successor.
root->right = deleteNode(root->right, successor->val);
}
return root;
}
private:
// Utility function to find minimum value node in the given subtree.
TreeNode* findMin(TreeNode* node) {
TreeNode* current = node;
while (current && current->left) {
current = current->left;
}
return current;
}
};
|
- Time Complexity: In the best case, which is a balanced BST, the time complexity is \(O(\log n)\), where \(n\) is the number of nodes. This is because, in a balanced BST, the height of the tree is \(\log n\), and in the worst case, you might need to traverse from the root to a leaf node. In the worst case, which is a skewed BST (e.g., each node has only one child), the time complexity degrades to \(O(n)\), where \(n\) is the number of nodes.
- Space Complexity: The space complexity is \(O(h)\), where \(h\) is the height of the tree. This space is used by the recursive call stack. In the best case of a balanced tree, the space complexity is \(O(\log n)\). In the worst case of a skewed tree, the space complexity becomes \(O(n)\).