代码随想录算法训练营 day 22: 235. 二叉搜索树的最近公共祖先 701.二叉搜索树中的插入操作 450.删除二叉搜索树中的节点

84 阅读3分钟

235. Lowest Common Ancestor of a Binary Search Tree

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”

 

Example 1:

Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
Output: 6
Explanation: The LCA of nodes 2 and 8 is 6.

Example 2:

Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
Output: 2
Explanation: The LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition.

Example 3:

Input: root = [2,1], p = 2, q = 1
Output: 2

 

Constraints:

  • The number of nodes in the tree is in the range [2, 105].
  • -109 <= Node.val <= 109
  • All Node.val are unique.
  • p != q
  • p and q will exist in the BST.

BST的公共祖先当然也可以按照普通树来做,后序遍历回溯,返回包含目标节点的节点,在父节点处做判断。 但作为BST,这题可以控制递归方向,结果是不算前序中序后序遍历,的遍历。 在每个节点判断当前节点跟两个目标节点的大小比较,从而决定递归的方向。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null) {
            return null;
        }

        //TreeNode nleft = lowestCommonAncestor(root.left, p, q);
        //TreeNode nright = lowestCommonAncestor(root.right, p, q);

        if(root.val == p.val || root.val == q.val) {
            return root;
        }
        else if((root.val > p.val && root.val < q.val) || (root.val < p.val && root.val > q.val)){
            //one left one right;
            return root;
        }
        //same direction
        else if(root.val < p.val){
            //go right
            return lowestCommonAncestor(root.right, p, q);
        }
        else if (root.val > p.val) {
            return lowestCommonAncestor(root.left, p, q);
        }

        return null;

    }
}

701. Insert into a Binary Search Tree

You are given the root node of a binary search tree (BST) and a value to insert into the tree. Return the root node of the BST after the insertion. It is guaranteed that the new value does not exist in the original BST.

Notice that there may exist multiple valid ways for the insertion, as long as the tree remains a BST after insertion. You can return any of them.

 

Example 1:

Input: root = [4,2,7,1,3], val = 5
Output: [4,2,7,1,3,5]
Explanation: Another accepted tree is:

Example 2:

Input: root = [40,20,60,10,30,50,70], val = 25
Output: [40,20,60,10,30,50,70,null,null,25]

Example 3:

Input: root = [4,2,7,1,3,null,null,null,null,null,null], val = 5
Output: [4,2,7,1,3,5]

 

Constraints:

  • The number of nodes in the tree will be in the range [0, 104].
  • -108 <= Node.val <= 108
  • All the values Node.val are unique.
  • -108 <= val <= 108
  • It's guaranteed that val does not exist in the original BST.

这题的思路不太好想,我一开始是用中序遍历插节点,结果处理不了目标比整个树的节点值都大的情形,还得补一个往尾巴上插节点的操作。 递归思路为:

  1. 每层递归返回在新树中的本节点
  2. 若当前节点值大于目标值,往左遍历。反之往右。
  3. 在遍历到null时,意味着应当在本递归处创建新节点,返回新建节点。
/**
 * 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 {

    public TreeNode insertIntoBST(TreeNode root, int val) {
        if(root == null) {
            TreeNode node = new TreeNode(val);
            return node;
        }

        if(root.val > val) {
            root.left = insertIntoBST(root.left, val);
        }
        if(root.val < val) {
            root.right = insertIntoBST(root.right, val);
        }

        return root;
    }
}

450. Delete Node in a BST

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.

 

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

 

Follow up:  Could you solve it with time complexity O(height of tree)?

这题也是思路不好找,判断条件很多。 递归思路为 每层递归返回在新树下的本处节点。 遍历到应删除节点时:

  1. 若左右子节点都为空,则为叶子,返回null
  2. 若仅有左孩子为空,返回右孩子
  3. 若仅有右孩子为空,返回左孩子。
  4. 若左右孩子都不为空,则将左孩子添加到右孩子的最左下孩子的左孩子处,返回右孩子。

起初的思路卡在4上,因为4只是一种构造法,相当于在删除父节点的同时,将左子树整个附加到右子树的左下角。我一开始的思路是将右子树的最左下角节点与当前待删除节点做对换,很明显工作量要大很多。

/**
 * 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 {
    public TreeNode deleteNode(TreeNode root, int key) {
        if(root == null) {
            return null;
        }

        if(root.val == key) {
            if(root.left == null && root.right == null) {
                return null;
            } else if(root.left == null) {
                return root.right;
            } else if(root.right == null) {
                return root.left;
            }
            else {
                //left right non-empty
                TreeNode tmp = root.right;
                while(tmp.left != null) {
                    tmp = tmp.left;
                }

                tmp.left = root.left;
                return root.right;
            }
        }

        root.left = deleteNode(root.left, key);
        root.right = deleteNode(root.right, key);

        return root;

    }
}