zoukankan      html  css  js  c++  java
  • 236. 二叉树的最近公共祖先

    给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

    百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

    示例 1:

    输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
    输出:3
    解释:节点 5 和节点 1 的最近公共祖先是节点 3 。
    示例 2:


    输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
    输出:5
    解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。

    解法一:递归 深度搜索

    通过深度搜索,不断递归,如果搜索到要查找的节点,那么返回true,同时左右节点中如果存在要查找的节点,也返回true,最大深度公共节点满足的条件是,左右子树都是true,或者根节点是要查找的节点并且左右子树存在一个为true

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
            if(root == NULL) return NULL;           //递归边界
            if(root == p || root == q) return root;
    
            //分解为求左子树的子问题和右子树的子问题,注意是后序遍历
            TreeNode* left_have = lowestCommonAncestor(root->left,p,q);     
            TreeNode* right_have = lowestCommonAncestor(root->right,p,q);   
            if(left_have && right_have) return root;        //左右子树都有则返回root
            else return left_have ? left_have : right_have;     //如果左右子树中有一个子问题没得到结果,则返回得到结果的子问题.
        }

    复杂度分析

    时间复杂度:O(N)O(N),其中 NN 是二叉树的节点数。二叉树的所有节点有且只会被访问一次,因此时间复杂度为 O(N)O(N)。

    空间复杂度:O(N)O(N) ,其中 NN 是二叉树的节点数。递归调用的栈深度取决于二叉树的高度,二叉树最坏情况下为一条链,此时高度为 NN,因此空间复杂度为 O(N)O(N)。

    解法二:记录父节点

    首先把为所有节点建立和父节点的关联,然后通过hash表查找要查找节点的父节点,并且存储在map中,通过对比找到父节点

    Map<Integer, TreeNode> parent = new HashMap<Integer, TreeNode>();
        Set<Integer> visited = new HashSet<Integer>();
    
        public void dfs(TreeNode root) {
            if (root.left != null) {
                parent.put(root.left.val, root);
                dfs(root.left);
            }
            if (root.right != null) {
                parent.put(root.right.val, root);
                dfs(root.right);
            }
        }
    
        public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
            dfs(root);
            while (p != null) {
                visited.add(p.val);
                p = parent.get(p.val);
            }
            while (q != null) {
                if (visited.contains(q.val)) {
                    return q;
                }
                q = parent.get(q.val);
            }
            return null;
        }

    复杂度分析

    时间复杂度:O(N)O(N),其中 NN 是二叉树的节点数。二叉树的所有节点有且只会被访问一次,从 p 和 q 节点往上跳经过的祖先节点个数不会超过 NN,因此总的时间复杂度为 O(N)O(N)。

    空间复杂度:O(N)O(N) ,其中 NN 是二叉树的节点数。递归调用的栈深度取决于二叉树的高度,二叉树最坏情况下为一条链,此时高度为 NN,因此空间复杂度为 O(N)O(N),哈希表存储每个节点的父节点也需要 O(N)O(N) 的空间复杂度,因此最后总的空间复杂度为 O(N)O(N)。

  • 相关阅读:
    使用Leangoo玩转故事地图
    用Leangoo做敏捷需求管理
    LEANGOO成员
    LEANGOO卡片
    给WebAPI的REST接口添加测试页面(三)
    使用Win2D在UWP程序中2D绘图(二)
    Visual Studio 2015的“转到定义”和“查看定义”出错的Bug
    使用Win2D在UWP程序中2D绘图(一)
    Windows 10 UWP程序标题栏设置
    .NET 4.6的RyuJIT尾递归优化的Bug
  • 原文地址:https://www.cnblogs.com/xiaoming521/p/14872059.html
Copyright © 2011-2022 走看看