在二叉树中找到两个节点的最近公共祖先

原创 2016年08月30日 17:21:54

程序员代码面试指南(左程云)读书笔记

 第三章

在二叉树中找到两个节点的最近公共祖先
题目:
      给定一棵二叉树的头节点head,以及这棵二叉树的两个节点o1和o2,请返回o1和o2的最近公共祖先节点。
解答:
       后序遍历二叉树,假设遍历到的当前结点为cur,因为是后序遍历,所以先处理cur的两颗子树,假设处理cur左子树时返回left,处理右子树时返回right.
      1,如果发现cur等于null,或者o1,o2。则返回cur.
      2,如果left和right都为空,说明cur整棵子树都没有发现过o1 和o2,返回null.
      3.如果left和right都不为空,说明左子树上发现过o1 和 o2,右子树上也发现过o1 和o2,说明o1 向上与o2向上的过程中,首次在cur相遇,返回cur.
      4,如果left和right是有一个为空,另一个不为空,假设不为空的那个记为node,此时又两种肯,要么node是o1或o2中的一个,要么node已经是o1和o2的最近公共祖先节点,此时直接返回node即可。

代码如下:
public TreeNode lowestAcnestor(TreeNode head,TreeNode o1,TreeNode o2){
    if(head==null){return head;}
    //在左子树中查找目标节点
    TreeNode left=lowestAcnestor(head.left,o1,o2);
    //在右子树中查找目标节点
    TreeNode right=lowestAcnestor(head.right,o1,o2);

     if(left!=null && right!=null){return head;}
     return left!=null?left:right;
}

public class TreeNode  {
           public  int val;
             public TreeNode  left;
            public TreeNode  right;
            public TreeNode (int val) {this. val = val; }
}
进阶问题:
         如果查询两个节点的最近公共祖先的操作十分频繁,想办法让单条查询的查询时间减少。
       这个问题其实是先花较大的力气建立一种记录,以后执行每次查询时就可以完全根据记录进行查询。 

结构一:建立二叉树中每个节点对应的父节点信息,是一张哈希表。
       如果对题目中的二叉树建立这种哈希表,如下图所示:


代码:
import java.util.HashMap;
import java.util.HashSet;

public class ParentNode2 {
private HashMap<TreeNode, TreeNode> map;
public  ParentNode2(TreeNode head) {
    map=new HashMap<TreeNode ,TreeNode>();
    if(head!=null){
        map.put(head, null);
        setMap(head);
    }
}
public void setMap(TreeNode head) {
    if(head==null){return ;}
    if(head.left!=null){map.put(head.left, head);}
    if(head.right!=null){map.put(head.right, head);}
    setMap(head.left);
    setMap(head.right);
}
public TreeNode query(TreeNode o1,TreeNode o2){
    HashSet<TreeNode> path=new HashSet<TreeNode>();
    while(map.containsKey(o1)){
        path.add(o1);
        o1=map.get(o1);
    }
    while(!path.contains(o2)){
        o2=map.get(o2);
    }
    return o2;}
}
结构二:
     直接建立任意两个节点之间的最近公共祖先记录,便于以后查询时直接查。
 过程如下:
       1,对二叉树的每颗子树(一共N课)都进行步骤2.
       2,假设子树的头节点为h,h所有的后代节点和h节点的最近公共祖先节点都是h,记录下来,h左子树的每个节点和h右子树的每个节点的最近公共祖先都是h,记录下来。
      为了保证记录不重复,设计一种好的实现方法是重点。
package com.chen.zuocengyun;

import java.util.HashMap;
//在二叉树中找到两个节点的最近公共祖先节点
public class ParentNode3 {
private HashMap<TreeNode, HashMap<TreeNode,TreeNode>> map;
 public ParentNode3(TreeNode head){
     map=new HashMap<TreeNode,HashMap<TreeNode,TreeNode>>();
     initMap(head);
     setMap(head);
 }
private void setMap(TreeNode head) {
       if(head==null){return;}
       headRecord(head.left,head);
       headRecord(head.right,head);
       subRecord(head);
       setMap(head.left);
       setMap(head.right);
}
private void headRecord(TreeNode n, TreeNode h) {
      if(n==null){return;}
      map.get(n).put(h, h);
      headRecord(n.left, h);
      headRecord(n.right, h);
}
private void subRecord(TreeNode head) {
if(head==null){
    return;
}    
    preLeft(head.left,head.right,head);
    subRecord(head.left);
    subRecord(head.right);
}
private void preLeft(TreeNode l, TreeNode r, TreeNode h) {
           if(l==null){return;}
           preRight(l,r,h);
           preLeft(l.left, r, h);
           preLeft(l.right,r,h);
}
private void preRight(TreeNode l, TreeNode r, TreeNode h) {
           if(r==null){return;}
           map.get(l).put(r, h);
           preRight(l, r.left, h);
           preRight(l, r.right, h);
}
private void initMap(TreeNode head) {
      if(head==null){return;}
      map.put(head, new HashMap<TreeNode,TreeNode>());
      initMap(head.left);
      initMap(head.right);
}

public TreeNode query(TreeNode o1,TreeNode o2){
    if(o1==o2){return o1;}
    if(map.containsKey(o1)){return map.get(o1).get(o2);}
    if(map.containsKey(o2)){return map.get(o2).get(o1);}
    return null;
}
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

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

题目:求二叉树中两个节点的最近公共祖先节点 一、该二叉树为搜索二叉树 搜索二叉树的特点: 任意一个节点的左子树的所有节点值都比该节点的值小,其右子树的所有节点值都比该节点的值大。 解决该问题方法: 从...

二叉树最近公共祖先问题(O(n) time 且只遍历一遍,O(1) Space (不考虑函数调用栈的空间))

Tarjan算法很精妙,但是使用了并查集,需要额外O(n)的存储空间。上面博客中给的第三个方法也是需要记录根到节点的路径,需要O(log n)空间,当然考虑到一般情况下我们遍历树都是递归的方式,所以本...

java--数据结构--二叉树的最近公共祖先

1.若是二叉搜索树思路: 如果p,q 比root小, 则LCA必定在左子树;如果p,q 比root大, 则LCA必定在右子树;若一小一大,则LCA是root /** * Definition f...

二叉树中找两个结点的最近公共祖先结点

一、搜索二叉树:第一变种是二叉树是一种特殊的二叉树:查找二叉树。也就是树是排序过的,位于左子树上的结点都比父结点小,而位于右子树的结点都比父结点大。我们只需要从根结点开始和两个结点进行比较。如果当前结...

查找二叉树某两个节点最近的共同祖先及改进方法

这个题目偶尔看到网上有个jie
  • J__King
  • J__King
  • 2014年09月09日 23:12
  • 1656

找出二叉树中某两个结点的第一个公共祖先

设计一个算法,找出二叉树中某两个结点的第一个公共祖先.。不得将额外的结点存储在另外的数据结构中。注意:这不一定是二叉查找树。 题目分析: 假设1:这个二叉树是二叉排序树(O(N)) 如果题目中的...

《程序员面试金典》--寻找二叉树中两个节点的第一个公共祖先(三种情况)

/***************************************************************************************************...
  • zdplife
  • zdplife
  • 2015年10月26日 19:21
  • 1743

二叉树中两个节点的最近公共祖先(leetcode)

leetcode题目地址https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/#/description二叉树构造...

LeetCode -- 查找最小公共祖先

LeetCode -- 查找最小公共祖先

经典算法:寻找最近公共祖先

题目 假设现在他知道了N个人的信息——他们的父亲是谁。给出两个人的名字,找出这两个人是否存在同一个祖先,如果存在,那么他们的所有共同祖先中辈分最低的一个是谁? 输入输出 每个测试点(输入文件)有...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:在二叉树中找到两个节点的最近公共祖先
举报原因:
原因补充:

(最多只允许输入30个字)