【40讲系列5】二叉树、二叉搜索树

一、理论

二分搜索树:

  1. 每个节点的键值大于左孩子;

  2. 每个节点的键值小于右孩子;

  3. 以左右孩子为根的子树仍为二分搜索树。

对于二分搜索树,要求掌握 插入、 查找、 删除 基本操作,以及

  查找最大值、最小值;

  给定一个数据,寻找前驱和后继,以及上界和下界

  某个元素的排名rank

  寻找第k大或小元素select

二、典型例题

☆☆①:验证二叉搜索树(LC98)

思路:中序遍历时,判断当前节点是否大于中序遍历的前一个节点,如果大于,满足BST,继续遍历;否则返回false。

中序遍历(递归):

class Solution {
    private TreeNode pre; // 前一个节点, 定义为全局的

    public boolean isValidBST(TreeNode root) {
        if (root == null) return true;
        // 访问左子树
        if(!isValidBST(root.left)){
            return false;
        }
        // 访问当前节点,如果当前节点<=中序遍历的前一个节点,直接返回false
        if (pre != null && pre.val >= root.val){
            return false;
        }
        pre = root;
        // 访问右子树
        return isValidBST(root.right);
    }
}

中序遍历(非递归):

class Solution {
    public boolean isValidBST(TreeNode root) {
        if (root == null) return true;
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode pre = null;
        while (root != null || !stack.isEmpty()){
            while (root != null){
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            if (pre != null && pre.val >= root.val){
                return false;
            }
            pre = root;
            root = root.right;
        }
        return true;
    }
}

☆☆②:二叉树的最近公共祖先(LC236)

class Solution {
    // 时间复杂度O(n)
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null)
            return null;
        if (p == root || q == root)  // 其中一个节点就在根节点的位置
            return root;
        TreeNode left = lowestCommonAncestor(root.left,p,q);
        TreeNode right = lowestCommonAncestor(root.right,p,q);
        if (left != null && right != null) return root;
        if (left == null) return right;
        if (right == null) return left;
        return null; // left和right都为空(即左右子树都不包含pq)
    }
}

③:二叉搜索树的最新公共祖先(LC235)

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        // 递归写法
        /*
        if (p.val < root.val && q.val < root.val){
            return lowestCommonAncestor(root.left,p,q);
        }
        if (p.val > root.val && q.val >root.val){
            return lowestCommonAncestor(root.right,p,q);
        }
        return root; // 对应三种情况
        */
        // 非递归写法
        while (root != null){
            if (p.val < root.val && q.val < root.val){
                root = root.left;
            }else if (p.val > root.val && q.val > root.val){
                root = root.right;
            }else{
                return root;
            }
        }
        return null;
    }
}

三、扩展例题

第一组:LeetCode104. 二叉树的最大深度LeetCode111. 二叉树的最小深度

第二组:LeetCode226. 翻转二叉树LeetCode100. 相同的树LeetCode101. 对称二叉树LeetCode222. 完全二叉树的节点个数LeetCode110. 平衡二叉树

第三组:LeetCode112. 路径总和LeetCode404. 左叶子之和

第四组:LeetCode257. 二叉树的所有路径LeetCode113. 路径总和 IILeetCode129. 求根到叶子节点数字之和LeetCode222. 完全二叉树的节点个数LeetCode437. 路径总和 III

第五组(BST相关问题):LeetCode783. 二叉搜索树节点最小距离LeetCode235. 二叉搜索树的最近公共祖先LeetCode98. 验证二叉搜索树LeetCode450. 删除二叉搜索树中的节点LeetCode108. 将有序数组转换为二叉搜索树LeetCode109. 有序链表转换二叉搜索树LeetCode230. 二叉搜索树中第K小的元素LeetCode236. 二叉树的最近公共祖先LeetCode530. 二叉搜索树的最小绝对差

原文地址:https://www.cnblogs.com/HuangYJ/p/14015247.html