package com.freetymekiyan.algorithms.other;

import com.freetymekiyan.algorithms.utils.Utils.TreeNode;

/**
 * Given a root of BST and a node's value. Delete the node with that value from the tree.
 * Return new root.
 * <p>
 * Tags: Tree
 */
public class DeleteANodeFromBinarySearchTree {

    /**
     * Tree. BST. Recursive. The Hibbard deletion.
     * Two stages: Search for the node while tracking the parent.
     * If the node is found, delete.
     * Recursive delete will take the root and return new root.
     * So that the subtree can be connected to its parent.
     * Base case:
     * When root is null, return null.
     * Recurrence relation:
     * If key < root.val, key is in left subtree.
     * | Recurse on the left subtree and update root.left with the result.
     * If key > root.val, key is in right subtree.
     * | Recurse on the right subtree and update root.right with the result.
     * Else key == root.val, the node is found, start to delete.
     * | If root is a leaf, return null.
     * | If root has one child, return that child.
     * | That combines to:
     * |   If root.left == null, return root.right.
     * |   Else if root.right == null, return root.left.
     * | Now root has two children. Find the in-order successor or predecessor.
     * | First replace root's value with the minimum value of right subtree.
     * | Then delete the value from right subtree with recursive call.
     * Return root.
     * http://quiz.geeksforgeeks.org/binary-search-tree-set-2-delete/
     */
    public TreeNode delete(int key, TreeNode root) {
        if (root == null) {
            return null;
        }
        if (key < root.val) {
            root.left = delete(key, root.left);
        } else if (key > root.val) {
            root.right = delete(key, root.right);
        } else { // Key is same as current root's val.
            // Node with only one child or no child.
            if (root.left == null) {
                return root.right;
            } else if (root.right == null) {
                return root.left;
            }
            // Node with two children: Get the inorder successor.
            root.val = getMin(root.right);
            // Delete the inorder successor.
            root.right = delete(root.val, root.right);
        }
        return root;
    }

    /**
     * Find the minimum value of BST.
     */
    private int getMin(TreeNode root) {
        int min = root.val;
        while (root.left != null) {
            min = root.left.val;
            root = root.left;
        }
        return min;
    }
}

add delete a node from BST