劍指Offer(Java版):二叉樹的深度

題目:輸入一棵二叉樹的根節點,求該數的深度。從根節點到葉結點依次進過的結點(含根,葉結點)造成樹的一條路徑,最長路徑的長度爲樹的深度。node

例如,以下圖的二叉樹的深度爲4,由於它從根節點到葉結點的最長的路徑包含4個結點(從根結點1開始,通過2和結點5,最終到達葉結點7)面試

咱們能夠從另外一種角度來理解樹的深度。若是一棵樹只有一個結點,它的 深度爲1,若是根節點只有左子樹而沒有右子樹,那麼樹的深度應該是其左子樹的深度+1.一樣若是根節點只有右子樹而沒有左子樹,那麼樹的深度應該是其右子 樹+1.若是既有左子樹又有右子樹,那概述的深度就是左、右子樹的深度的較大值加1.。算法

利用這個思路,咱們能夠用遞歸來實現代碼:編程

package cglib;函數

class BinaryTreeNode{
    int data;
    
    BinaryTreeNode leftNode;
    BinaryTreeNode rightNode;
    
}性能

public class jiekou {遞歸

    //普通二叉樹求深度  
    public int treeDepth(BinaryTreeNode root){  
        if(root == null)  
            return 0;  
        System.out.println("treeDepth遞歸");
        int nLeft = treeDepth(root.leftNode);
        
        System.out.println("nLeft="+nLeft);
        System.out.println("nRight前treeDepth遞歸");
        int nRight = treeDepth(root.rightNode);
        System.out.println("nRight後");
        System.out.println("nRight="+nRight);
        return (nLeft > nRight)?(nLeft+1):(nRight+1);  
    }   
        public static void main(String[] args){  
            BinaryTreeNode root=new BinaryTreeNode();
            BinaryTreeNode node1=new BinaryTreeNode();
            BinaryTreeNode node2=new BinaryTreeNode();
            BinaryTreeNode node3=new BinaryTreeNode();
            BinaryTreeNode node4=new BinaryTreeNode();
            BinaryTreeNode node5=new BinaryTreeNode();
            BinaryTreeNode node6=new BinaryTreeNode();
            root.leftNode=node1;
            root.rightNode=node2;
            node1.leftNode=node3;
            node1.rightNode=node4;
            node2.rightNode=node5;
            node4.leftNode=node6;
            root.data=1;
            node1.data=2;
            node2.data=3;
            node3.data=4;
            node4.data=5;
            node5.data=6;
            node6.data=7;
            jiekou test = new jiekou();  
            System.out.println(test.treeDepth(root));  
        }
    }class

輸出:4test

 

 

若是公司對編程能力有較高的要求,面試官可能會追加一個與前面的問題相關但難度較大的問題,好比,應聘者作完上面的問題後,面試官追問:效率

 

題目二:輸入一棵二叉樹的根節點,判斷該樹是否是平衡的二叉樹。若是某二叉樹中任意結點的左右子樹的深度相差不超過1,那麼它就是一棵平衡二叉樹。

須要重複遍歷結點屢次的解法,簡單但不足以打動面試官

有了求二叉樹的深度的經驗以後再解決這個問題,咱們很容易就能想到一個思路:在遍歷樹的每一個結點的時候,調用函數TreeDepth獲得它的左右子樹的深度。若是每一個結點的左右子樹的深度相差不超過1,按照定義它就是一棵平衡的二叉樹。這種思路實現的代碼以下:

 

package cglib;

class BinaryTreeNode{
    int data;
    
    BinaryTreeNode leftNode;
    BinaryTreeNode rightNode;
    
}

public class jiekou {

    //普通二叉樹求深度  
    public int treeDepth(BinaryTreeNode root){  
        if(root == null)  
            return 0;  
        System.out.println("treeDepth遞歸");
        int nLeft = treeDepth(root.leftNode);
        
        System.out.println("nLeft="+nLeft);
        System.out.println("nRight前treeDepth遞歸");
        int nRight = treeDepth(root.rightNode);
        System.out.println("nRight後");
        System.out.println("nRight="+nRight);
        return (nLeft > nRight)?(nLeft+1):(nRight+1);  
    }
    
    public boolean isBalanced(BinaryTreeNode root){  
        if(root ==null)  
            return true;  
        int left = treeDepth(root.leftNode);  
        int right = treeDepth(root.rightNode);  
        int diff = left - right;  
        if(diff > 1 || diff <-1)  
            return false;  
        return isBalanced(root.leftNode) && isBalanced(root.rightNode);  
    }  
        public static void main(String[] args){  
            BinaryTreeNode root=new BinaryTreeNode();
            BinaryTreeNode node1=new BinaryTreeNode();
            BinaryTreeNode node2=new BinaryTreeNode();
            BinaryTreeNode node3=new BinaryTreeNode();
            BinaryTreeNode node4=new BinaryTreeNode();
            BinaryTreeNode node5=new BinaryTreeNode();
            BinaryTreeNode node6=new BinaryTreeNode();
            root.leftNode=node1;
            root.rightNode=node2;
            node1.leftNode=node3;
            node1.rightNode=node4;
            node2.rightNode=node5;
            node4.leftNode=node6;
            root.data=1;
            node1.data=2;
            node2.data=3;
            node3.data=4;
            node4.data=5;
            node5.data=6;
            node6.data=7;
            jiekou test = new jiekou();  
            System.out.println(test.treeDepth(root));
            System.out.println(test.isBalanced(root));
        }
    }

 

輸出:

treeDepth遞歸
treeDepth遞歸
treeDepth遞歸
nLeft=0
nRight前treeDepth遞歸
nRight後
nRight=0
nLeft=1
nRight前treeDepth遞歸
treeDepth遞歸
treeDepth遞歸
nLeft=0
nRight前treeDepth遞歸
nRight後
nRight=0
nLeft=1
nRight前treeDepth遞歸
nRight後
nRight=0
nRight後
nRight=2
nLeft=3
nRight前treeDepth遞歸
treeDepth遞歸
nLeft=0
nRight前treeDepth遞歸
treeDepth遞歸
nLeft=0
nRight前treeDepth遞歸
nRight後
nRight=0
nRight後
nRight=1
nRight後
nRight=2
4
treeDepth遞歸
treeDepth遞歸
nLeft=0
nRight前treeDepth遞歸
nRight後
nRight=0
nLeft=1
nRight前treeDepth遞歸
treeDepth遞歸
treeDepth遞歸
nLeft=0
nRight前treeDepth遞歸
nRight後
nRight=0
nLeft=1
nRight前treeDepth遞歸
nRight後
nRight=0
nRight後
nRight=2
treeDepth遞歸
nLeft=0
nRight前treeDepth遞歸
treeDepth遞歸
nLeft=0
nRight前treeDepth遞歸
nRight後
nRight=0
nRight後
nRight=1
treeDepth遞歸
nLeft=0
nRight前treeDepth遞歸
nRight後
nRight=0
treeDepth遞歸
treeDepth遞歸
nLeft=0
nRight前treeDepth遞歸
nRight後
nRight=0
nLeft=1
nRight前treeDepth遞歸
nRight後
nRight=0
treeDepth遞歸
nLeft=0
nRight前treeDepth遞歸
nRight後
nRight=0
treeDepth遞歸
nLeft=0
nRight前treeDepth遞歸
nRight後
nRight=0
true

上面的代碼當然簡潔,但咱們也注意到因爲一個結點會被重複遍歷屢次,這種 思路的時間效率不高。例如在函數isBalanced中輸入上圖中的二叉樹,咱們將首先判斷根節點是否是平衡的。此時咱們網函數TreeDepth輸入左 子樹的根節點時須要遍歷結點4,5,7.接下來判斷以結點2爲根節點的子樹是否是平衡樹的時候,仍然會遍歷結點4,5,7.毫無疑問,重複遍歷同一個結點 會影響性能。接下來咱們尋找不須要重複遍歷的算法。

package cglib;

class BinaryTreeNode{
    int data;
    
    BinaryTreeNode leftNode;
    BinaryTreeNode rightNode;
    
}

public class jiekou {

    //普通二叉樹求深度  
    public int treeDepth(BinaryTreeNode root){  
        if(root == null)  
            return 0;  
        System.out.println("treeDepth遞歸");
        int nLeft = treeDepth(root.leftNode);
        
        System.out.println("nLeft="+nLeft);
        System.out.println("nRight前treeDepth遞歸");
        int nRight = treeDepth(root.rightNode);
        System.out.println("nRight後");
        System.out.println("nRight="+nRight);
        return (nLeft > nRight)?(nLeft+1):(nRight+1);  
    }
    
    public boolean isBalanced(BinaryTreeNode root){  
        if(root ==null)  
            return true;  
        int left = treeDepth(root.leftNode);  
        int right = treeDepth(root.rightNode);  
        int diff = left - right;  
        if(diff > 1 || diff <-1)  
            return false;  
        return isBalanced(root.leftNode) && isBalanced(root.rightNode);  
    }  
    
    //高效率的判斷是不是一棵平衡二叉樹  
    public boolean isBalanced2(BinaryTreeNode root){  
        int depth = 0;  
        return isBalanced2(root,depth);  
    }  
    public boolean isBalanced2(BinaryTreeNode root,int depth){  
        if(root == null){  
            depth = 0;  
            return true;  
        }  
        int left = 0,right = 0;  
        if(isBalanced2(root.leftNode,left) && isBalanced2(root.rightNode,right)){  
            int diff = left-right;  
            if(diff <= 1 && diff >= -1){  
                depth = 1+(left > right?left : right);  
                return true;  
            }  
        }  
        return false;  
    }  
        public static void main(String[] args){  
            BinaryTreeNode root=new BinaryTreeNode();
            BinaryTreeNode node1=new BinaryTreeNode();
            BinaryTreeNode node2=new BinaryTreeNode();
            BinaryTreeNode node3=new BinaryTreeNode();
            BinaryTreeNode node4=new BinaryTreeNode();
            BinaryTreeNode node5=new BinaryTreeNode();
            BinaryTreeNode node6=new BinaryTreeNode();
            root.leftNode=node1;
            root.rightNode=node2;
            node1.leftNode=node3;
            node1.rightNode=node4;
            node2.rightNode=node5;
            node4.leftNode=node6;
            root.data=1;
            node1.data=2;
            node2.data=3;
            node3.data=4;
            node4.data=5;
            node5.data=6;
            node6.data=7;
            jiekou test = new jiekou();  
            System.out.println(test.treeDepth(root));
            System.out.println(test.isBalanced(root));
            System.out.println(test.isBalanced2(root));
        }
    }
   

在上面的代碼中,咱們用後序遍歷的方式遍歷整棵二叉樹。在遍歷某結點的左右子樹結點以後,咱們就能夠根據它的左右子樹的深度判斷它時不時平衡的,並獲得當前結點的深度。當最後遍歷到樹的根節點的時候,也就判斷了整棵二叉樹是否是平衡二叉樹。

相關文章
相關標籤/搜索