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

来源:互联网 发布:java项目怎么绑定域名 编辑:程序博客网 时间:2024/06/04 23:18

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

 第三章

在二叉树中找到两个节点的最近公共祖先
题目:
      给定一棵二叉树的头节点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;
}
}
0 0
原创粉丝点击