剑指offer(java):求树中两个结点的最低公共祖先

题目:java

    树中两个节点的最低公共祖先。.net

最近公共祖先简称LCA(Lowest Common Ancestor),所谓LCA,是当给定一个有根树T时,对于任意两个结点u、v,找到一个离根最远的结点x,使得x同时是u和v的祖先,x 即是u、v的最近公共祖先。指针

 

思路一:排序

    输入两个树节点,求他们的最低公共祖先,内存

——若是是二叉树,并且是二叉搜索树,那么是能够找到公共节点的。get

二叉搜索树都是排序过的,位于左子树的节点都比父节点小,而位于右子树上面的节点都比父节点大。ast

  • 若是当前节点的值比两个结点 的值都大,那么最低的共同的父节点必定是在当前节点的左子树中,因而下一步遍历当前节点的左子节点。
  • 若是当前节点的值比两个结点的值都小,那么最低的共同的父节点必定是在当前节点的右子树中,因而下一步遍历当前节点的右子节点。
  • 这样从上到下,找到的第一个在两个输入结点的值之间的节点,就是最低的公共祖先。

package cglib;class

class TreeNode {
    int data;
    TreeNode left;
    TreeNode right;
    }效率

public class List1
{  
    public static TreeNode getLastCommonParent(TreeNode root,TreeNode a,TreeNode b)
    {
            if (root==null || a==null || b==null)
                return null;
            while (root != null) {
                if (root.data > a.data  && root.data  > b.data )
                    root = root.left;
                else if (root.data < a.data && root.data < b.data)
                    root = root.right;
                else
                    return root;
            }
            return null;
    }
    
    public static void main(String args[]){
        TreeNode n1 = new TreeNode();
        TreeNode n2 = new TreeNode();
        TreeNode n3 = new TreeNode();
        TreeNode n4 = new TreeNode();
        TreeNode n5 = new TreeNode();
        TreeNode n6 = new TreeNode();
        TreeNode n7 = new TreeNode();
       
        n1.left=n2;
        n1.right=n3;
        n2.left=n4;
        n2.right=n5;
        n3.left=n6;
        n3.right=n7;
        n1.data=10;
        n2.data=8;
        n3.data=13;
        n4.data=4;
        n5.data=9;
        n6.data=12;
        n7.data=17;
        // 搜索二叉树
        //              10
        //           /       \
        //         8         13
        //        /  \       /     \
        //      4    9  12    17
        System.out.println(n1.data);
        System.out.println(n6.data);
        System.out.println(n7.data);
        TreeNode parent=getLastCommonParent(n1, n6, n7);  
        System.out.println(parent.data);
    }import


    }

 

输出:

10
12
17
13

 

思路二:

若是这棵树是普通的树,并且树中结点没有指向父结点的指针,解法以下:

 

思路三:

咱们能够用深度优先搜索,从叶子节点向上,标记子树中出现目标节点的状况。若是子树中有目标 节点,标记为那个目标节点,若是没有,标记为null。显然,若是左子树、右子树都有标记,说明就已经找到最小公共祖先了。若是在根节点为p的左右子树中 找p、q的公共祖先,则一定是p自己。

换个角度,能够这么想:若是一个节点左子树有两个目标节点中的一个,右子树没有,那这个节点 确定不是最小公共祖先。若是一个节点右子树有两个目标节点中的一个,左子树没有,那这个节点确定也不是最小公共祖先。只有一个节点正好左子树有,右子树也 有的时候,才是最小公共祖先。

 

package cglib;

class TreeNode {
    int data;
    TreeNode left;
    TreeNode right;
    }

public class List1
{   
    //两个节点的最低公共祖先,参数为两个节点  
    public static TreeNode getLastCommonParent(TreeNode root,TreeNode a,TreeNode b)
    {
        
            //发现目标节点则经过返回值标记该子树发现了某个目标结点
        //若是在根节点为a的左右子树中找a、b的公共祖先,则一定是a自己。
        //同理,若是在根节点为b的左右子树中找a、b的公共祖先,则一定是b自己。
         if (root == null || root == a || root == b)
             return root;
            //查看左子树中是否有目标结点,没有为null  
         TreeNode left = getLastCommonParent(root.left, a, b);  
            //查看右子树是否有目标节点,没有为null  
         TreeNode right = getLastCommonParent(root.right, a, b);  
            //都不为空,说明左右子树都有目标结点,则公共祖先就是自己  
            if (left != null&&right != null)
                return root;  
            //若是发现了目标节点,则继续向上标记为该目标节点  
            return left == null ? right : left;  
          
    }
    
    public static void main(String args[]){
        TreeNode n1 = new TreeNode();
        TreeNode n2 = new TreeNode();
        TreeNode n3 = new TreeNode();
        TreeNode n4 = new TreeNode();
        TreeNode n5 = new TreeNode();
        TreeNode n6 = new TreeNode();
        TreeNode n7 = new TreeNode();
       
        n1.left=n2;
        n1.right=n3;
        n2.left=n4;
        n2.right=n5;
        n3.left=n6;
        n3.right=n7;
        n1.data=1;
        n2.data=2;
        n3.data=3;
        n4.data=4;
        n5.data=5;
        n6.data=6;
        n7.data=7;
        // 搜索二叉树
        //            1
        //          /   \
        //         2     3
        //        / \   / \
        //      4    5 6   7
        System.out.println(n1.data);
        System.out.println(n6.data);
        System.out.println(n7.data);
        TreeNode parent=getLastCommonParent(n1, n6, n7);  
        System.out.println(parent.data);
    }


    }

 

输出:

1
6
7
3

 

以上解法须要对同一个结点重复遍历不少次,效率较低,若是容许使用辅助内存,则能够有效率更高的方法,解法以下:

 

package cglib;

import java.util.Stack;

class TreeNode {
    int data;
    TreeNode left;
    TreeNode right;
    }

public class List1
{   
      
    public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){    
        Stack<TreeNode> stackp = new Stack<TreeNode>();        
        Stack<TreeNode> stackq = new Stack<TreeNode>();    
        getPath(root, p, stackp);        
        getPath(root, q, stackq);    
        return lowestCommonAncestor(stackp, stackq);  
        }    
    private static TreeNode lowestCommonAncestor(Stack<TreeNode> stackp, Stack<TreeNode> stackq)    {    
        TreeNode target = null;        
        while (!stackp.isEmpty() && !stackq.isEmpty() && stackp.peek() == stackq.peek())    
        {        
            target = stackp.peek();        
            stackp.pop();        
            stackq.pop();    
            }        
        return target;    
        }    
    private static boolean getPath(TreeNode root, TreeNode p, Stack<TreeNode> stackp)    {    
        // TODO Auto-generated method stub    
        if (root == null)        
            return false;    
        if (root == p)        
        {            
            stackp.push(root);    
            return true;    
            }        
        else        
        {            
            if (getPath(root.left, p, stackp) || getPath(root.right, p, stackp))
            {                
                stackp.push(root);        
                return true;        
                }        
            }        
        return false;    
        }
    /***
     *
     * 这个代码在实现过程当中,是当找到给定节点的时候才将路径依次压入stack中的,
     * 也就是说,两个stack的栈顶都是存放着root节点。
     * 所以,此时就应该找两条路径分离开以前的最后一个节点,
     * 此节点就是所求的最低公共祖先。
     * @param args
     */
    
    public static void main(String args[]){
        TreeNode n1 = new TreeNode();
        TreeNode n2 = new TreeNode();
        TreeNode n3 = new TreeNode();
        TreeNode n4 = new TreeNode();
        TreeNode n5 = new TreeNode();
        TreeNode n6 = new TreeNode();
        TreeNode n7 = new TreeNode();
       
        n1.left=n2;
        n1.right=n3;
        n2.left=n4;
        n2.right=n5;
        n3.left=n6;
        n3.right=n7;
        n1.data=1;
        n2.data=2;
        n3.data=3;
        n4.data=4;
        n5.data=5;
        n6.data=6;
        n7.data=7;
        // 搜索二叉树
        //            1
        //          /   \
        //         2     3
        //        / \   / \
        //      4    5 6   7
        System.out.println(n1.data);
        System.out.println(n6.data);
        System.out.println(n7.data);
        TreeNode parent=lowestCommonAncestor(n1, n6, n7);  
        System.out.println(parent.data);
    }


    }

输出: 1 6 7 3

相关文章
相关标签/搜索