zoukankan      html  css  js  c++  java
  • 【LeetCode】235.二叉搜索树的最近公共祖先(递归+迭代,详细图解,java实现)

    前言:

    这道题其实是236.二叉搜索树的最近公共祖先的特殊情况版,其中的二叉树变为了二叉搜索树。

    我在另一篇博客中也有详细解析,地址是:【LeetCode】236.二叉树的最近公共祖先(后序遍历 DFS ,清晰图解)

    有兴趣的朋友可以看看,加深对二叉树的理解。

    题目

    地址:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/

    image-20200622002853891

    解析:

    我们来复习一下二叉搜索树(BST)的性质:

    1. 节点 NN 左子树上的所有节点的值都小于等于节点 NN 的值
    2. 节点 NN 右子树上的所有节点的值都大于等于节点 NN 的值
    3. 左子树和右子树也都是 BST

    解题思路:

    祖先的定义: 若节点 p 在节点 root的左(右)子树中,或 p = root,则称 root是 p的祖先。

    Picture1.png

    最近公共祖先的定义: 设节点 root为节点 p,q的某公共祖先,若其左子节点 root.left和右子节点 root.right都不是 p,q 的公共祖先,则称 root是 “最近的公共祖先” 。

    根据以上定义,若 root是 p,q 的 最近公共祖先 ,则只可能为以下情况之一:

    1. p和 q在 root的子树中,且分列 root 的 异侧(即分别在左、右子树中);
    2. p = root,且 q在 root 的左或右子树中;
    3. q = root,且 p 在 root的左或右子树中;

    Picture2.png

    本题给定了两个重要条件:① 树为 二叉搜索树 ,② 树的所有节点的值都是 唯一 的。根据以上条件,可方便地判断 p,q与 root的子树关系,即:

    • 若 root.val < p.val ,则 p 在 root 右子树 中;
    • 若 root.val > p.val,则 p 在 root 左子树 中;
    • 若 root.val = p.val,则 p和 root 指向 同一节点

    方法一:迭代

    1. 循环搜索:

      当节点 root为空时跳出;

      1. 当 p, q 都在 root的 右子树 中,则遍历至 root.right ;
      2. 否则,当 p, q 都在 root的 左子树 中,则遍历至 root.left;
      3. 否则,说明找到了 最近公共祖先 ,跳出。
    2. 返回值: 最近公共祖先 root 。

    复杂度分析:
    • 时间复杂度 O(N) 其中 NN 为二叉树节点数;每循环一轮排除一层,二叉搜索树的层数最小为 log NlogN (满二叉树),最大为 NN (退化为链表)。
    • 空间复杂度 O(1) 使用常数大小的额外空间。

    代码:

    class Solution {
        public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
            while(root != null) {
                if(root.val < p.val && root.val < q.val) // p,q 都在 root 的右子树中
                    root = root.right; // 遍历至右子节点
                else if(root.val > p.val && root.val > q.val) // p,q 都在 root 的左子树中
                    root = root.left; // 遍历至左子节点
                else break;
            }
            return root;
        }
    }
    

    优化:若可保证 p.val < q.val,则在循环中可减少判断条件。

    class Solution {
        public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
            if(p.val > q.val) { // 保证 p.val < q.val
                TreeNode tmp = p;
                p = q;
                q = tmp;
            }
            while(root != null) {
                if(root.val < p.val) // p,q 都在 root 的右子树中
                    root = root.right; // 遍历至右子节点
                else if(root.val > q.val) // p,q 都在 root 的左子树中
                    root = root.left; // 遍历至左子节点
                else break;
            }
            return root;
        }
    }
    

    方法二:递归

    1. 递推工作:
      1. 当 p, q 都在 root的 右子树 中,则开启递归 root.right 并返回;
      2. 否则,当 p, q 都在 root 的 左子树 中,则开启递归 root.left 并返回;
    2. 返回值: 最近公共祖先 root。
    复杂度分析:
    • 时间复杂度 O(N) : 其中 N为二叉树节点数;每循环一轮排除一层,二叉搜索树的层数最小为 logN (满二叉树),最大为 N(退化为链表)。
    • 空间复杂度 O(N): 最差情况下,即树退化为链表时,递归深度达到树的层数 NN
    代码:
    class Solution {
        public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
            if(root.val < p.val && root.val < q.val)
                return lowestCommonAncestor(root.right, p, q);
            if(root.val > p.val && root.val > q.val)
                return lowestCommonAncestor(root.left, p, q);
            return root;
        }
    }
    
  • 相关阅读:
    ZOJ 2859 Matrix Searching
    URAL 1102. Strange Dialog
    ZOJ 1986 Bridging Signals
    POJ 3233 Matrix Power Series
    POJ 1836 Alignment
    POJ 3267 The Cow Lexicon
    ZOJ 3471 Most Powerful
    IIS:HTTP 错误 403.9 禁止访问:连接的用户过多
    使用Command对象执行数据库操作
    C#类型转换
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13308041.html
Copyright © 2011-2022 走看看