天天看点

二叉树总结之最近公共祖先

二叉树的最近公共祖先

题目

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

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

例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]

二叉树总结之最近公共祖先

示例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。因为根据定义最近公共祖先节点可以为节点本身。      

解题思路

假设 root 是 p, q 的最近公共祖先,那么就可以有以下三种情况:

  1. p 和 q 在 root 的子树中,且分列 root 的左、右子树中;
  2. p = root,且 q 在 root 的左或右子树中;
  3. q = root,且 p 在 root 的左或右子树中;

在这里,我们使用二叉树先序遍历的方式来对此二叉树进行搜索;当遇到节点 p 或者 q 的时候返回。自底向上回溯,当节点 p, q 在节点 root 的异侧时,节点 root 即为最近公共祖先,则向上返回 root 。

递归函数解析:

  1. 终止条件:当遇到根节点时,则直接返回 null; 当 root 等于 p 或者 q 的时候,返回 root。
  2. 单层递归逻辑:开启递归左子节点,返回值记为 left; 开启递归右子节点,返回值记为 right。
  3. 返回值:当 left 和 right 都为 null 时,说明没有找到 p 和 q, 返回 null;当 left 和 right 都不为空时,则 p 和 q 分别位于 root 俩侧,所以 root 为最近的祖先节点,返回 root; 当 left 为空,right 不为空,说明 p,q 都不在 root 的左子树中,则直接返回 right, 反之,返回 left。

代码实现

/**
 * 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 || root == p || root == q){
            return root;
        }

        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        if(left == null && right == null) return null;
        if (left == null) {
            return right;
        }

        if (right == null) {
            return left;
        }

        return      

复杂度分析

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

二叉搜索树的最近公共祖先

Hello, 大家好,今天是8月更文的第 4 天,今天要和大家分享的关于二叉树的算法题是:给定一个二叉搜索树,找到该树中俩个指定节点的最近的公共祖先。

题目

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

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

例如:给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]

二叉树总结之最近公共祖先

示例1:

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

示例2:

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

思路分析

  1. 如果当前节点的值大于 p 和 q 的值,说明 p 和 q 应该在当前节点的左子树,因此将当前节点移动到它的左子节点;
  2. 如果当前节点的值小于 p 和 q 的值,说明 p 和 q 应该在当前节点的右子树,因此将当前节点移动到它的右子节点;
  3. 如果当前节点的值不满足上述两条要求,那么说明当前节点就是分岔点。此时,p 和 q 要么在当前节点的不同的子树中,要么其中一个就是当前节点。
/**
 * 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.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);
        }
        // 第三种情况,p,q不在同一子树,只能是p,q分别在一左一右,或者,p,q其中一个是根节点,都返回root
        return root;      

复杂度分析

  1. 时间复杂度:O(n),其中 n 是给定的二叉搜索树中的节点个数。
  2. 空间复杂度:O(1)。