首页 > 代码库 > 50、树中两个节点的公共祖先

50、树中两个节点的公共祖先

详细的询问:

 

1、该树是二叉查找树? 最近公共祖先----二叉查找树:(http://www.lintcode.com/problem/lowest-common-ancestor/)
思路:利用左子树特点:左子树 < 根 <= 右,输入节点跟根节点比较,都小于,在左子树,都大约右子树,递归的去遍历;找到当前节点在两个输入大小之间,当前节点就是。
递归和非递归
技术分享
public class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) {
            return null;
        }
        if (root.val > Math.max(p.val, q.val)) {
            return lowestCommonAncestor(root.left, p, q);
        } else if (root.val < Math.min(p.val, q.val)) {
            return lowestCommonAncestor(root.right, p, q);
        } else{
            return root;
        }
    }
}
非递归:
public class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        while(true){
            if (root.val > Math.max(p.val, q.val)){
                root = root.left;
            } else if (root.val < Math.min(p.val, q.val)){
                root = root.right;
            }
            else{
                break;
            }
        }
        return root;
    }
}
View Code

2、该树有指向父节点的指针

最近公共祖先----普通的树有指向父节点的指针:
思路:转换为求两个链表的第一个公共节点。从叶子节点到根节点都是由一个pparent连起来的链表。
对齐或栈
技术分享
方法1:计算两个链表长度,len = 长度之差,对齐链表,然后依次遍历比较
/**
 * Definition of ParentTreeNode:
 * 
 * class ParentTreeNode {
 *     public ParentTreeNode parent, left, right;
 * }
 */
public class Solution {
    /**
     * @param root: The root of the tree
     * @param A, B: Two node in the tree
     * @return: The lowest common ancestor of A and B
     */
    public ParentTreeNode lowestCommonAncestorII(ParentTreeNode root,
                                                 ParentTreeNode A,
                                                 ParentTreeNode B) {
        
        int a_L = getL(A);
        int b_L = getL(B);
        int diff = a_L - b_L;
        ParentTreeNode l = A;
        ParentTreeNode s = B;
        if(diff < 0){
            l = B;
            s = A;
            diff = b_L - a_L;
        }
        while(diff > 0) {
            l = l.parent;
            diff--;
        }
        while(l != null && s != null && l != s) {
            l = l.parent;
            s = s.parent;
        }
       
        return l;        
    }
    public int getL(ParentTreeNode node){
        int len = 0;
        ParentTreeNode pnode = node;
        while(pnode != null) {
            pnode = pnode.parent;
            len++;
        }
        return len;
    }
}
方法2:将两个链表存入栈或数组,逆序输出比较,直到找到第一个不相等的。
View Code

3、最近公共祖先----普通树,没有指针()

1)ab在树里,后序遍历,递归
技术分享
public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) return null;
        
        if (root == p || root == q) return root;
        
        // Post order traveral
        TreeNode l = lowestCommonAncestor(root.left, p, q);
        TreeNode r = lowestCommonAncestor(root.right, p, q);
        
        if (l != null && r != null) {
            return root;
        } else {
            return l != null ? l : r;
        }
    }
View Code

2)可能不在树里

思路: 在二叉树中来搜索p和q,然后从路径中找到最后一个相同的节点即为父节点,我们可以用递归来实现.后序遍历二叉树,得到从根节点到目标节点的“路径”。
方法一、
  1)判断改点在不在子树中covers()
  2)公共祖先helper()分同边,异边
改方法每次都会重复访问在不在子树,
 
技术分享
public class Solution {

    public TreeNode lowestCommonAncestor3(TreeNode root, TreeNode A, TreeNode B) {
       if(!covers(root,A) || !covers(root,B)){
           return null;
       }
       return Helper(root, A, B);
    }
    
    //判断该节点node是否在当前节点root的子树里
    public boolean covers(TreeNode root, TreeNode node){
        if(root == null) {
            return false;
        }
        if(root == node){
            return true;//当前节点即为node
        }
        return covers(root.left, node) || covers(root.right, node);//节点在当前节点的左右子树里
    }
    //找公共节点
    public TreeNode Helper(TreeNode root, TreeNode A, TreeNode B) {
         // write your code here
        if(root == null) {
            return null;
        }
        if (root == A || root == B){
            return root;
        }
        boolean a_i_L = covers(root.left, A);
        boolean b_i_L = covers(root.left, B);
        //不在同一边
        if(a_i_L != b_i_L){
            return root;
        }
        //在通一边
        TreeNode child_side = b_i_L ?root.left : root.right;
        return Helper(child_side, A, B);
    }
}
View Code

方法二:构造一个结构类,两种方法。

技术分享
class ResultType {
    public boolean a_exist, b_exist;
    public TreeNode node;
    ResultType(boolean a, boolean b, TreeNode n) {
        a_exist = a;
        b_exist = b;
        node = n;
    }
}

public class Solution {
    public TreeNode lowestCommonAncestor3(TreeNode root, TreeNode A, TreeNode B) {
        // write your code here
        ResultType rt = helper(root, A, B);
        if (rt.a_exist && rt.b_exist)
            return rt.node;
        else
            return null;
    }

    public ResultType helper(TreeNode root, TreeNode A, TreeNode B) {
        if (root == null)
            return new ResultType(false, false, null);
            
        ResultType left_rt = helper(root.left, A, B);
        ResultType right_rt = helper(root.right, A, B);
        
        boolean a_exist = left_rt.a_exist || right_rt.a_exist || root == A;
        boolean b_exist = left_rt.b_exist || right_rt.b_exist || root == B;
        
        if (root == A || root == B)
            return new ResultType(a_exist, b_exist, root);

        if (left_rt.node != null && right_rt.node != null)
            return new ResultType(a_exist, b_exist, root);
        if (left_rt.node != null)
            return new ResultType(a_exist, b_exist, left_rt.node);
        if (right_rt.node != null)
            return new ResultType(a_exist, b_exist, right_rt.node);

        return new ResultType(a_exist, b_exist, null);
    }
}
View Code

技术分享技术分享

 

 

 

 
 

50、树中两个节点的公共祖先