二叉樹求最大最小葉子節點距離

  • 題目描述:

有一棵二叉樹,樹上每一個點標有權值,權值各不相同,請設計一個算法算出權值最大的葉節點到權值最小的葉節點的距離。二叉樹每條邊的距離爲1,一個節點通過多少條邊到達另外一個節點爲這兩個節點之間的距離。java

給定二叉樹的根節點root,請返回所求距離。node

  • 思路:

先求最大最小葉子節點,再求兩節點的LCA(最近公共祖先),求兩節點到LCA距離。算法

首先得先明白如何求LCA(LCA屬於比較經典的一類考點,定要掌握)。this

  • 最近祖先節點:spa

最近祖先節點就是從根節點遍歷到給定節點時的最後一個相同節點。.net

如上圖,H和J的最低祖先節點是A。設計

由於從根節點Root到H的鏈路爲:   Root     A    C    Hcode

從根節點Root到J的鏈路爲:   Root   A    D   Jblog

查看鏈路節點可知,A是最後一個相同節點,也就是最近公共父節點或者說最低祖先節點是A。遞歸

實現LCA有兩種方式,遞歸和非遞歸,此處僅介紹遞歸方式。

  • LCA思路:

若是給定pRoot是NULL,即空樹,則返回的公共節點天然就是NULL;

若是給定pRoot與兩個節點中任何一個相同,說明,pRoot在就是所要找的兩個節點之一,則直接返回pRoot,代表在當前鏈路中找到至少一個節點;

若是給定pRoot不是兩個節點中任何一個,則說明,須要在pRoot的左右子樹中從新查找,此時有三種狀況:兩個節點都在左子樹上;兩個節點都在右子樹上;一個在左子樹,一個在右子樹上;具體來講,就是:

  • 狀況一:若是左子樹查找出的公共節點是NULL,則代表從左子樹根節點開始到左子樹的全部葉子節點等全部節點中,沒有找到兩個節點中的任何一個,這就說明,這兩個節點不在左子樹上,不在左子樹,則一定在右子樹上;
  • 狀況二:若是右子樹查找的公共節點是NULL,說明在右子樹中沒法找到任何一個節點,則兩個節點一定在左子樹上;
  • 狀況三: 若是左右子樹查找的公共節點都不是NULL,說明左右子樹中各包含一個節點,則當前節點pRoot就是最低公共節點,返回就能夠了。

       三種狀況是互斥的, 只能是其中之一。

public TreeNode GetLastCommonParent( TreeNode pRoot, TreeNode pNode1, TreeNode pNode2){  
	    if( pRoot == null ) //說明是空樹,不用查找了,也就找不到對應節點,則返回NULL  
	        return  null;  
	  
	    if( pRoot == pNode1 || pRoot == pNode2 )//說明在當前子樹的根節點上找到兩個節點之一  
	        return pRoot;  
	  
	    TreeNode   pLeft = GetLastCommonParent( pRoot.left, pNode1, pNode2);  //左子樹中的查找兩個節點並返回查找結果  
	    TreeNode   pRight = GetLastCommonParent( pRoot.right, pNode1, pNode2);//右子樹中查找兩個節點並返回查找結果  
	  
	    if( pLeft == null )//若是在左子樹中沒有找到,則判定兩個節點都在右子樹中,能夠返回右子樹中查詢結果;不然,須要結合左右子樹查詢結果共同判定  
	        return pRight;  
	    if ( pRight == null )//若是在右子樹中沒有找到,則判定兩個節點都在左子樹中,能夠返回左子樹中查詢結果;不然,須要結合左右子樹查詢結果共同判定  
	        return pLeft;  
	      
	    return pRoot;//若是在左右子樹中都找兩個節點之一,則pRoot就是最低公共祖先節點,返回便可。  
	}

參考地址:http://blog.csdn.net/beitiandijun/article/details/41970417

知道LCA實現以後,就簡單多了。

  • Java代碼實現
import java.util.*;

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;
    public TreeNode(int val) {
        this.val = val;
    }
}*/
public class Tree {
    private TreeNode maxNode = new TreeNode(Integer.MIN_VALUE);
	private TreeNode minNode = new TreeNode(Integer.MAX_VALUE);
    
    public int getDis(TreeNode root) {
        // write code here
        getMaxMin(root);//找到最大最小葉子節點
        TreeNode lcaNode = getLCA(root);//找LCA
        int a = getNodeDis(lcaNode, maxNode);//最大值葉子節點到LCA的距離;
        int b = getNodeDis(lcaNode, minNode);//最小值葉子節點到LCA的距離;
        return a+b;
    }
    
    // 先找到最大最小葉子節點
	public void getMaxMin(TreeNode root) {
		if (root == null) {
			return;
		}
		if (root.left == null && root.right == null) {
			if (root.val > maxNode.val) {
				maxNode = root;
			} else if (root.val < minNode.val) {
				minNode = root;
			}
		}
		getMaxMin(root.left);
		getMaxMin(root.right);
	}

	// LCA最近公共祖先
	public TreeNode getLCA(TreeNode root) {
		if (root == null) {// 說明是空樹
			return null;
		}
		if (root.val == maxNode.val || root.val == minNode.val) {// 在當前樹的根節點上找到兩個節點之一
			return root;
		}
		TreeNode leftNode = getLCA(root.left);// 左子樹中的查找兩個節點並返回查找結果
		TreeNode rightNode = getLCA(root.right);// 右子樹中查找兩個節點並返回查找結果
		if (leftNode == null) {// 左子樹中沒找到,則必定在右子樹上
			return rightNode;
		} else if (rightNode == null) {// 右子樹沒找到必定在左子樹上
			return leftNode;
		} else {// 左右子樹均找到一個節點,則根節點爲最近公共祖先
			return root;
		}
	}
    
    //獲取葉子節點到LCA距離
	public int getNodeDis(TreeNode lcaNode, TreeNode node){
		if(lcaNode==null){
			return -1;
		}
		if(lcaNode.val==node.val){
			return 0;
		}
        //三種狀況:兩個均在左子樹;兩個均在右子樹;一左一右,因此不能用if-elseif結構
		int distance = getNodeDis(lcaNode.left, node);//左子樹未找到兩個節點之一
		if(distance==-1){
			distance = getNodeDis(lcaNode.right, node);
		}
        if(distance!=-1){
			return distance+1;
		}
		
		return -1;
	}

 

 

知識是須要一點一點累積的!

相關文章
相關標籤/搜索