首页 > 其他分享 >二叉树两个节点的最近公共祖先问题

二叉树两个节点的最近公共祖先问题

时间:2022-10-06 14:13:08浏览次数:82  
标签:Info head ancestor 祖先 findB findA 二叉树 null 节点

二叉树两个节点的最近公共祖先问题

作者:Grey

原文地址:

博客园:二叉树两个节点的最近公共祖先问题

CSDN:二叉树两个节点的最近公共祖先问题

题目描述

给定一棵二叉树的头节点 head,和另外两个节点 a 和 b , 返回 a 和 b 的最低公共祖先。

题目链接见:LeetCode 236. Lowest Common Ancestor of a Binary Tree

主要思路:

本题也是利用二叉树的递归套路来解。

定义好 Info 信息

    public static class Info {
        public Info(boolean findA, boolean findB, TreeNode ancestor) {
            this.findA = findA;
            this.findB = findB;
            this.ancestor = ancestor;
        }
        private boolean findA;
        private boolean findB;
        private TreeNode ancestor;

    }

其中

findA表示能否在当前(子)树下找到 a 节点;

findB表示能否在当前(子)树下找到 b 节点;

ancestor表示当前两个节点的最低公共祖先是什么。

首先考虑一些边界条件,例如

if (a == null) {
    // a 为 null,不管 b 是否为 null,公共祖先都是 b
    return b;
}
if (b == null) {
    // b 为 null, 不管 a 是否为 null,公共祖先都是 a
    return a;
}

定义递归函数

Info p(TreeNode head, TreeNode a, TreeNode b)

递归含义是:以 head 为头的树,a 和 b 的公共祖先是什么,封装成 Info 返回。

接下来看递归函数的主要逻辑

首先是 base case,如果 head 为 null,则 findA = false,findB = false,a 和 b 的公共祖先也是 null

        if (head == null) {
            return new Info(false, false, null);
        }

分析了 base case,接下来是普遍情况,如果 head 不为 null,则去左树收集信息,去右树也收集信息,然后把左右两树的信息整合成 head 的信息返回

// 左树收集信息
Info leftInfo = p(head.left, a, b);
// 右树收集信息
Info rightInfo = p(head.right, a, b);

// 整合
......

最后,我们需要把左右两树返回的信息进行整合,首先,以 head 为头的树,findA的取值取决于如下三种情况:

情况1,左树包含 a,即 leftInfo.findA

情况2,右树包含 a,即 rightInfo.findA

情况3,head 就是 a

三个情况有一个满足,以 head 为头的树 findA = true,

findB类似,

即下述代码所表达的含义

//  这
boolean findA = leftInfo.findA || rightInfo.findA || head == a;
boolean findB = leftInfo.findB || rightInfo.findB || head == b;

接下来看两个节点的最低公共祖先,首先,如果左树上找到 a 和 b,那么 leftInfo.ancestor 就是 a 和 b 的最低公共祖先;

如果右树上找到 a 和 b,那么 rightInfo.ancestor 就是 a 和 b 的最低公共祖先;

如果左右树一边找到一个,则 head 就是 a 和 b 的最低公共祖先;

如果 a 和 b 在树上都找不到,即findA = false, findB = false,那么 a 和 b 的最低公共祖先就是 null。

即下述代码逻辑

        
        if (findA && findB) {
            if (leftInfo.findA && leftInfo.findB) {
                return new Info(true, true, leftInfo.ancestor);
            } else if (rightInfo.findA && rightInfo.findB) {
                return new Info(true, true, rightInfo.ancestor);
            }
            return new Info(true, true, head);
        }
        return new Info(findA, findB, null);

完整代码见

class Solution {
    public static TreeNode lowestCommonAncestor(TreeNode head, TreeNode a, TreeNode b) {
        if (a == null) {
            return b;
        }
        if (b == null) {
            return a;
        }
        // o1和o2都不为null
        return p(head, a, b).ancestor;
    }

    public static Info p(TreeNode head, TreeNode a, TreeNode b) {
        if (head == null) {
            return new Info(false, false, null);
        }
        Info leftInfo = p(head.left, a, b);
        Info rightInfo = p(head.right, a, b);
        boolean findA = leftInfo.findA || rightInfo.findA || head == a;
        boolean findB = leftInfo.findB || rightInfo.findB || head == b;
        if (findA && findB) {
            if (leftInfo.findA && leftInfo.findB) {
                return new Info(true, true, leftInfo.ancestor);
            } else if (rightInfo.findA && rightInfo.findB) {
                return new Info(true, true, rightInfo.ancestor);
            }
            return new Info(true, true, head);
        }
        return new Info(findA, findB, null);
    }

    public static class Info {
        public Info(boolean findA, boolean findB, TreeNode ancestor) {
            this.findA = findA;
            this.findB = findB;
            this.ancestor = ancestor;
        }

        private boolean findA;
        private boolean findB;
        private TreeNode ancestor;

    }
}

时间复杂度为O(N)(即一次后序遍历的时间复杂度)

更多

算法和数据结构笔记

标签:Info,head,ancestor,祖先,findB,findA,二叉树,null,节点
From: https://www.cnblogs.com/greyzeng/p/16757504.html

相关文章

  • 链表中间节点
    slow一次走一步,fast一次走两步。那么当fast到达链表的末尾时,slow必然位于中间。ListNode*middleNode(ListNode*head){ListNode*slow=head;......
  • 删除节点
    ListNode*deleteNode(ListNode*head,intval){if(head->val==val){head=head->next;returnhead;}ListNode......
  • 删除倒数第K个节点
    ListNode*getKthFromEnd(ListNode*head,intk){ListNode*fast=head;ListNode*slow=head;//因为头结点开始所以要从1开始for(i......
  • 101.对称二叉树 100.相同的树
    注意compare比较的只是左右节点!!!/***Definitionforabinarytreenode.*publicclassTreeNode{*intval;*TreeNodeleft;*TreeNoderight;......
  • 226.翻转二叉树,前序遍历解法
    /***Definitionforabinarytreenode.*publicclassTreeNode{*intval;*TreeNodeleft;*TreeNoderight;*TreeNode(){}*......
  • 剑☞offer 两个链表的第一个公共节点
    题目描述:给定两个单链表的头节点 headA 和 headB ,请找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。题目数据 保证 整个链式结构中不存......
  • 二叉树的最小深度
    二叉树的最小深度一、题目描述给定一个二叉树,找出其最小深度。最小深度是从根节点到最近的叶子节点的最短路径上的节点数量。实例输入:root=[3,9,20,null,null,15,7]......
  • IDEA 项目视图保存节点展开状态
    没兴趣看过程的,请直接跳转到「解决方案」部分。问题现象IDEA折叠再展开之后,之前展开的状态就没有了(若gif未自动播放,可在新标签页打开):不像Eclipse可以保存展开状......
  • 关于 SAP UI5 所有控件的共同祖先 - sap.ui.base.ManagedObject
    ManagedObject的新子类是通过调用ManagedObject.extend创建的,并且可以使用本文介绍的以下托管功能。托管属性表示ManagedObject的状态。它们可以存储简单数据类型(如“......
  • 代码随想录day15 | 102.二叉树的层序遍历 226.反转二叉树 101.对称二叉树
    102.二叉树的层序遍历题目|文章1.迭代思路1.创建一个队列2.确定每一层的节点个数,对每一层进行遍历,将结果输出。实现点击查看代码classSolution{public:ve......