Delete node in a binary search tree

LeetCode problem 450. Delete Node in a BST.

## Problem 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:

1. Search for a node to remove.
2. If the node is found, delete the node.

Follow up
Can you solve it with time complexity `O(height of tree)`?

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**: []

Constraints
* The number of nodes in the tree is in the range `[0, 104]`.
* `-105 <= Node.val <= 105`
* Each node has a **unique** value.
* `root` is a valid binary search tree.
* `-105 <= key <= 105`

## Analysis

We can first use the method of Search in a binary search tree to locate the node to be deleted. This can be done recursively, and at each level of recursion we can keep track of whether we have stepped into the left subtree or the right subtree.

If we did not find the node to delete, we do nothing and just return root.

Otherwise, if we have found the node to delete, there are several cases analyze:

Case 1: The node to be deleted has no children.

For the deleted node, We just need to change the left child / right child of its parent (if exists) to `null`.
Case 2: The node to be deleted has only one child.

For the deleted node, We just need to change the left child / right child of its parent (if exists) to the only child of this node.
Case 3: The node to be deleted has both children.
This is the most complicated case. We must proceed carefully to figure out how the nodes are rearranged.
Let **node D** be the node to be deleted. One method is to make use of the right subtree of node D (**subtree A**) to take over node D's position. The steps are as follows:
1. Find the minimum node of subtree A. Let this be **node M**.
2. For node M, keep a record of its right subtree (**subtree B**).
3. Now for subtree B, one of the two possible rearrangements will happen:
	* If the root of subtree A has no left child, then node M must be the right child of node D. We just need to set the left subtree of node D as the left child of subtree A.
	* If the root of subtree A has a left child, then we need to do the following:
		1. Pop out node M from subtree A.
		2. Let the parent of node M take over subtree B (i.e. set subtree B as the left child of node M's parent).
		3. Now for node M:
			+ Set its left child to the left child of node D.
			+ Set its right child to the rearranged subtree A.

After deleting node D, we can traverse back from the recursion, and return the root.
Illustration

### Complexity analysis

#### Time complexity

* The time complexity to search for the node to delete + search for the minimum element in its right subtree take is O(*height of tree*).
* After finding these two nodes, rearranging them takes O(1) time.

So total time complexity is **O(*height of tree*)**.

#### Space complexity

Stack
The recursion to find the node to delete has O(*height of tree*) complexity on stack.
Heap
Since we did not allocate any new objects, the space complexity on heap is O(1).
So our total space complexity is **O(*height of tree*)**.

## Solution

### C++

```
/\*\*
 \* 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 {
private:
 // delete smallest node from the right subtree
 // return smallest node (to pull up to the deleted node's position)
 static TreeNode\* deleteSmallestNode(TreeNode\* root) {
 TreeNode \*parent = nullptr, \*child = root;
 while (child->left != nullptr) {
 parent = child;
 child = child->left;
 }
 TreeNode \*smallest = child;
 parent->left = smallest->right;
 return smallest;
 }

public:
 TreeNode\* deleteNode(TreeNode\* root, const int& key) {
 if (root == nullptr) {
 return root;
 }

 // find target node
 TreeNode \*left = root->left, \*right = root->right;
 if (root->val > key) {
 // delete in left subtree
 root->left = deleteNode(left, key);
 return root;
 }
 else if (root->val < key) {
 // delete in right subtree
 root->right = deleteNode(right, key);
 return root;
 }

 // at this point, root != nullptr, root->val == key
 // hence root is the node to be deleted

 // case 1: both children are nullptr
 if ((left == nullptr) && (right == nullptr)) {
 delete root;
 return nullptr;
 }
 // case 2: exactly one children is nullptr
 else if ((left == nullptr) || (right == nullptr)) {
 TreeNode \*subTree = (left != nullptr) ? left : right;
 delete root;
 return subTree;
 }
 // case 3: node to delete has both children
 // i.e. root->left != nullptr && root->right != nullptr
 else {
 // if root's right subtree root has no left child
 // i.e. the right subtree node is the smallest value in right subtree
 if (right->left == nullptr) {
 delete root;
 root = right;
 right->left = left;
 return root;
 }
 // otherwise root's right subtree root has left child
 // we have to:
 // 1. delete the smallest node
 // 2. rearrange the right subtree
 // 3. pull up the smallest node to the positon of deleted node
 else {
 TreeNode \*smallest = deleteSmallestNode(right);
 delete root;
 smallest->left = left;
 smallest->right = right;
 return smallest;
 }
 }
 }
};

```

### Java

```
/\*\*
 \* Definition for a binary tree node.
 \* public class TreeNode {
 \* int val;
 \* TreeNode left;
 \* TreeNode right;
 \* TreeNode() {}
 \* TreeNode(int val) { this.val = val; }
 \* TreeNode(int val, TreeNode left, TreeNode right) {
 \* this.val = val;
 \* this.left = left;
 \* this.right = right;
 \* }
 \* }
 \*/
class Solution {

 // delete smallest node from the right subtree
 // return smallest node (to pull up to the deleted node's position)
 private static TreeNode deleteSmallestNode(TreeNode root) {
 TreeNode parent = null, child = root;
 while (child.left != null) {
 parent = child;
 child = child.left;
 }
 TreeNode smallest = child;
 parent.left = smallest.right;
 return smallest;
 }

 public TreeNode deleteNode(TreeNode root, int key) {
 if (root == null) {
 return root;
 }

 // find target node
 TreeNode left = root.left, right = root.right;
 if (root.val > key) {
 // delete in left subtree
 root.left = deleteNode(left, key);
 return root;
 }
 else if (root.val < key) {
 // delete in right subtree
 root.right = deleteNode(right, key);
 return root;
 }

 // at this point, root != null, root.val == key
 // hence root is the node to be deleted

 // case 1: both children are null
 if ((left == null) && (right == null)) {
 return null;
 }
 // case 2: exactly one children is null
 else if ((left == null) || (right == null)) {
 TreeNode subTree = (left != null) ? left : right;
 return subTree;
 }
 // case 3: node to delete has both children
 // i.e. root.left != null && root.right != null
 else {
 // if root's right subtree root has no left child
 // i.e. the right subtree node is the smallest value in right subtree
 if (root.right.left == null) {
 root = right;
 root.left = left;
 return root;
 }
 // otherwise root's right subtree root has left child
 // we have to:
 // 1. delete the smallest node
 // 2. rearrange the right subtree
 // 3. pull up the smallest node to the positon of deleted node
 else {
 TreeNode smallest = deleteSmallestNode(right);
 smallest.left = left;
 smallest.right = right;
 return smallest;
 }
 }
 }
}

```

## Notes

* The main purpose of using recursion is to enable us to keep track of whether we have stepped into the left subtree or right subtree at each step.
* For searching the minimum node in the right subtree of the deleted node, we have to keep track of the parent, so that we can use that parent to join the subtree of the minimum node.
* Remember that after we have located the node to be deleted and deleted node, we have to return the new root of the rearranged subtree.

## See also

* Search in a binary search tree
* Insert into a binary search tree