1.問題描述
寫一個程序求一棵二叉樹相距最遠的兩個節點之間的距離
如下圖:
2.分析與解法
對於任意一個節點,以該節點為根,假設這個根有k個孩子節點,那么距離最遠的兩個節點U與V之間的路徑與這個根節點的關系有兩種。
1).若路徑經過Root,則U和V屬於不同子樹的,且它們都是該子樹中到根節點最遠的節點,否則跟它們的距離最遠相矛盾
2).如果路徑不經過Root,那么它們一定屬於根的k個子樹之一,並且它們也是該子樹中相距最遠的兩個頂點
因此,問題就可以轉化為在字數上的解,從而能夠利用動態規划來解決。
設第K棵子樹中相距最遠的兩個節點:Uk和Vk,其距離定義為d(Uk,Vk),那么節點Uk或Vk即為子樹K到根節點Rk距離最長的節點。不失一般性,我們設Uk為子樹K中道根節點Rk距離最長的節點,其到根節點的距離定義為d(Uk,R)。取d(Ui,R)(1<=i<=k)中最大的兩個值max1和max2,那么經過根節點R的最長路徑為max1+max2+2,所以樹R中相距最遠的兩個點的距離為:max{d(U1,V1),…, d(Uk,Vk),max1+max2+2}。
3.代碼實現
編程之美給出的代碼如下:
//數據結構定義 struct NODE { NODE* pLeft; //左孩子 NODE* pRight; //右孩子 int nMaxLeft; //左孩子中的最長距離 int nMaxRight; //右孩子中的最長距離 char chValue; //該節點的值 }; int nMaxLen=0; //尋找樹中最長的兩段距離 void FindMaxLen(NODE* pRoot) { //遍歷到葉子節點,返回 if(pRoot==NULL) { return; } //如果左子樹為空,那么該節點的左邊最長距離為0 if(pRoot->pLeft==NULL) { pRoot->nMaxLeft=0; } //如果右子樹為空,那么該節點的右邊最長距離為0 if(pRoot->pRight==NULL) { pRoot->nMaxRight=0; } //如果左子樹不為空,遞歸尋找左子樹最長距離 if(pRoot->pLeft!=NULL) { FindMaxLen(pRoot->pLeft); } //如果右子樹不為空,遞歸尋找右子樹最長距離 if(pRoot->pRight!=NULL) { FindMaxLen(pRoot->pRight); } if(pRoot->pLeft!=NULL) { int nTempMax=0; if(pRoot->pLeft->nMaxLeft > pRoot->pLeft->nMaxRight) { nTempMax=pRoot->pLeft->nMaxLeft; } else { nTempMax=pRoot->pLeft->nMaxRight; } pRoot->nMaxLeft=nTempMax+1; } //計算右子樹最長節點距離 if(pRoot->pRight!=NULL) { int nTempMax=0; if(pRoot->pRight->nMaxLeft > pRoot->pRight->nMaxRight) { nTempMax= pRoot->pRight->nMaxLeft; } else { nTempMax= pRoot->pRight-> nMaxRight; } pRoot->nMaxRight=nTempMax+1; } //更新最長距離 if(pRoot->nMaxLeft+pRoot->nMaxRight > nMaxLen) { nMaxLen=pRoot->nMaxLeft+pRoot->nMaxRight; } }
依據二叉樹尋找最大深度的常規思想,又有代碼如下:
struct BTNode { int data; BTNode* pLeft; BTNode* pRight; }; int maxDis = -1; int findMaxDis(BTNode* pRoot) { if(pRoot == NULL) return 0; int maxLeft = findMaxDis(pRoot->pLeft) ; int maxRight = findMaxDis(pRoot->pRight); if(maxLeft + maxRight > maxDis) { maxDis = maxLeft + maxRight; } return maxLeft > maxRight ? maxLeft+1 : maxRight+1; }
后一段代碼為自寫 沒有驗證其正確性。