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)。

  • 相关阅读:
    【反射】Java反射机制
    Composer教程之常用命令
    Composer教程之基础用法
    Composer教程之初识Composer
    Composer 的结构详解
    现代 PHP 新特性系列(七) —— 内置的 HTTP 服务器
    现代 PHP 新特性系列(一) —— 命名空间
    现代 PHP 新特性系列(二) —— 善用接口
    现代 PHP 新特性系列(三) —— Trait 概览
    现代 PHP 新特性系列(四) —— 生成器的创建和使用
  • 原文地址:https://www.cnblogs.com/xiaoming521/p/14872059.html
Copyright © 2011-2022 走看看