ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【算法】求二叉树两个节点的最低公共祖先节点

2022-01-23 01:02:51  阅读:246  来源: 互联网

标签:head 祖先 fatherMap 算法 二叉树 node1 node2 节点


左程云算法与数据结构课 https://www.bilibili.com/video/BV13g41157hK?p=2&spm_id_from=pageDriver

题目

给定两个二叉树的节点node1和node2,找到他们的最低公共祖先节点。

题解

解法一

设置一个 HashMap 保存节点与该节点的父节点(设根节点的父节点为本身),然后再用一个集合 set1 保存 node1 的全部祖先节点,对node2往上求祖先节点,看是否在 set1 中,若在,则这个节点即为最低公共祖先节点。

//前提:node1和node2一定属于head为头的树
//返回node1和node2的最低公共祖先
public static Node lca(Node head, Node node1, Node node2) {
    HashMap<Node, Node> fatherMap = new HashMap<>(); //保存节点与该节点的父节点
    fatherMap.put(head, head); //根节点的父节点为本身
    process(head, fatherMap);  //求所有节点的父节点
    HashSet<Node> set1 = new HashSet<>(); //node1 的祖先节点集合
    Node cur = node1;
    //求 node1 的祖先节点,并放入set1中 
    while (cur != fatherMap.get(cur)) { //回溯到根节点时停止
        set1.add(cur);
        cur = fatherMap.get(cur);
    }
    set1.add(head);

    //求 node2 的祖先节点
    cur = node2;
    while (!set1.contains(cur)) { //set1 中含该节点时停止
        cur = fatherMap.get(cur);
    }
    //该节点即为最低公共祖先节点
    return cur;
}
//递归求除根节点外所有节点的父节点,保存在 fatherMap 中
private static void process(Node head, HashMap<Node, Node> fatherMap) {
    if (head == null) {
        return;
    }
    fatherMap.put(head.left, head);
    fatherMap.put(head.right, head);
    process(head.left, fatherMap);
    process(head.right, fatherMap);
}

解法二

在二叉树中有两种情况:

  • 其中一个节点是另一个节点的子孙,则最低公共祖先节点是那个作为祖先的节点
  • 两个节点不存在祖孙关系,则最低公共祖先节点是最近的公共祖先

image-20220122232822714

image-20220122232855230

试想这么一个递归操作:

  • 基本事件是当一棵子树的头节点为 null 或 为 node1 或 node2 时,就返回这个头节点。
  • 对左右子树作递归,获得左右子树的返回值。递归的返回值只有四种可能:null 、node1 、node2,两节点的最低公共祖先节点。
  • 当左子树返回值不空,右子树返回值不空(即两节点分别落于左右子树上),返回头节点(该头节点即为最低公共祖先节点)。
  • 当不满足左右子树返回值均不空这个条件时,若左子树返回值不空时返回该值(可能为node1 、node2,两节点的最低公共祖先节点),否则返回右子树的值(可能为null 、node1 、node2,两节点的最低公共祖先节点)。

在这个递归操作中,有以下情况:

  • 若一棵子树不包含 node1 和 node2,那么它左右子树返回的值必定是 null,它往上返回的值也必定是 null;(a)

  • 若一棵子树只包含 node1 和 node2 两者之一,这里假设包含的是node1,那么它往上返回的值是 node1;(b)

  • 若一棵子树包含node1 和 node2 两者,

    • 若 node1 和 node2 存在祖孙关系,那么node1 和 node2 只能存在于该树的左右子树其中一棵,假设 node1 为 祖先(node1是最低公共祖先节点),则该树的左右子树返回值必定是node1和null,根据递归操作的最后一条原则,不管是左子树返回值是node1 还是右子树返回值是node1,都能保证该树往上返回的是 node1。

    • 若 node1 和 node2 不存在祖孙关系,分别落于它的左右子树中 ,根据(b),则左右子树返回的值分别是node1和node2,即满足左右子树返回值均不空,那么该子树往上返回的值是头节点。(c)

    • 若 node1 和node2 不存在祖孙关系并且均落于该树的其中一棵子树上,假设均落于右子树上,则右子树的子树中必定存在这么一棵子树满足上面(c)条件,这棵子树返回值是头节点,也就是最低公共祖先节点,那么右子树最终返回的值也是该最低公共节点。左子树满足(a)条件,返回 null。故该树往上返回的值是最低公共祖先节点。

通过上面的刨析,就能写出下面优美的代码了。

public static Node lowestCommonAncestor(Node head, Node node1, Node node2) {
    if (head == null || head == node1 || head == node2) { //base case
        return head;
    }
    Node left = lowestCommonAncestor(head.left, node1, node2);
    Node right = lowestCommonAncestor(head.right, node1, node2);
    if (left != null && right != null) {
        return head;
    }
    return left != null ? left : right;
}

标签:head,祖先,fatherMap,算法,二叉树,node1,node2,节点
来源: https://www.cnblogs.com/hzyuan/p/15835556.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有