有一棵二叉樹,樹上每一個點標有權值,權值各不相同,請設計一個算法算出權值最大的葉節點到權值最小的葉節點的距離。二叉樹每條邊的距離爲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有兩種方式,遞歸和非遞歸,此處僅介紹遞歸方式。
若是給定pRoot是NULL,即空樹,則返回的公共節點天然就是NULL;
若是給定pRoot與兩個節點中任何一個相同,說明,pRoot在就是所要找的兩個節點之一,則直接返回pRoot,代表在當前鏈路中找到至少一個節點;
若是給定pRoot不是兩個節點中任何一個,則說明,須要在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實現以後,就簡單多了。
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; }
知識是須要一點一點累積的!