劍指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

相關文章
相關標籤/搜索