1. 程式人生 > >尋找二叉樹中的最低公共祖先結點----LCA(Lowest Common Ancestor )問題(遞歸)

尋找二叉樹中的最低公共祖先結點----LCA(Lowest Common Ancestor )問題(遞歸)

求解 mon etl 轉換成 right push_back 問題 off ==

轉自 劍指Offer之 - 樹中兩個結點的最低公共祖先

題目:

求樹中兩個節點的最低公共祖先。

思路一:

——如果是二叉樹,而且是二叉搜索樹,那麽是可以找到公共節點的。

二叉搜索樹都是排序過的,位於左子樹的節點都比父節點小,而位於右子樹上面的節點都比父節點大。

如果當前節點的值比兩個結點 的值都大,那麽最低的共同的父節點一定是在當前節點的左子樹中,於是下一步遍歷當前節點的左子節點。

如果當前節點的值比兩個結點的值都小,那麽最低的共同的父節點一定是在當前節點的右子樹中,於是下一步遍歷當前節點的右子節點。

這樣從上到下,找到的第一個在兩個輸入結點的值之間的節點,就是最低的公共祖先。

題目和代碼參考:http://blog.csdn.net/u012243115/article/details/46875537。

思路二:

如果這棵樹不是二叉搜索樹,甚至連二叉樹都不是,而只是普通的樹。

——如果有指向父節點的指針,那麽這個題目轉換成了求,兩個雙向鏈表的第一個公共結點的問題。

思路三:

這棵樹是普通的樹,而且這個樹中的結點沒有指向父節點的指針。

——遍歷這個樹,看以這個節點為根的子樹是否包含這兩個節點,如果包含,判斷這個節點的子節點是否包含,

——知道子節點都不包含而這個當前的節點包含,那麽這個節點就是最低的公共祖先。

ps.這裏存在大量的重復遍歷,效率不高。

思路三:

這棵樹是普通的樹,而且這個樹中的結點沒有指向父節點的指針。

——用兩個鏈表分別保存從根節點到輸入的兩個結點的路徑,然後把問題轉換成兩個鏈表的最後公共節點。

代碼:

(這裏假設樹是普通二叉樹,用思路三求解)

#include <iostream>  
#include <list>  
using namespace std;  
  
struct TreeNode  
{  
    int m_nValue;  
    TreeNode *m_pLeft;  
    TreeNode *m_pRight;  
    TreeNode(){}  
    TreeNode(int value):m_nValue(value),m_pLeft(NULL),m_pRight(NULL){}  
};  
  
//得到pNode結點的路徑,放入path中 也可以用棧來實現 ,遞歸的本質就是一個壓棧和出棧的過程
// 本題可為劍指offer原題P252,其解法可參考面試題25(P143) bool GetNodePath(TreeNode * pRoot , TreeNode *pNode , list<TreeNode *> &path) { if(pRoot == NULL) return false; path.push_back(pRoot); bool found = false; if(pRoot == pNode) { found = true; return found; } // 註意理解這裏的遞歸問題 found = GetNodePath(pRoot->m_pLeft , pNode , path) || GetNodePath(pRoot->m_pRight , pNode , path); if(!found) path.pop_back(); return found; } //找到兩條路徑的最後一個公共結點即是公共祖先 TreeNode * GetLastCommonNode(const list<TreeNode *> &path1 , const list<TreeNode*> &path2) { list<TreeNode *>::const_iterator iterator1 = path1.begin(); list<TreeNode *>::const_iterator iterator2 = path2.begin(); TreeNode *pLast = NULL; while(iterator1 != path1.end() && iterator2 != path2.end()) { if(*iterator1 == *iterator2) pLast = *iterator1; iterator1++; iterator2++; } return pLast; } TreeNode * GetLastCommonNodeParent(TreeNode *pRoot , TreeNode *pNode1 , TreeNode *pNode2) { if(pRoot == NULL || pNode1 == NULL || pNode2 == NULL) return NULL; list<TreeNode *> path1; GetNodePath(pRoot , pNode1 , path1); list<TreeNode *> path2; GetNodePath(pRoot , pNode2 , path2); return GetLastCommonNode(path1 , path2); } TreeNode * findLCA(TreeNode *pRoot , TreeNode *pNode1 , TreeNode *pNode2) { if(pRoot == NULL) return NULL; if(pRoot == pNode1 || pRoot == pNode2) return pRoot; TreeNode *left_lca = findLCA(pRoot->m_pLeft , pNode1 , pNode2); TreeNode *right_lca = findLCA(pRoot->m_pRight , pNode1 , pNode2); if(left_lca && right_lca ) return pRoot; return (left_lca != NULL) ? left_lca : right_lca; } int main() { TreeNode *p1 = new TreeNode(1); TreeNode *p2 = new TreeNode(2); TreeNode *p3 = new TreeNode(3); TreeNode *p4 = new TreeNode(4); TreeNode *p5 = new TreeNode(5); TreeNode *p6 = new TreeNode(6); TreeNode *p7 = new TreeNode(7); TreeNode *p8 = new TreeNode(8); TreeNode *p9 = new TreeNode(9); TreeNode *p10 = new TreeNode(10); p1->m_pLeft = p2; p1->m_pRight = p3; p2->m_pLeft = p4; p2->m_pRight = p5; p3->m_pLeft = p6; p3->m_pRight = p7; p4->m_pLeft = p8; p4->m_pRight = p9; p5->m_pLeft = p10; TreeNode *p; p = GetLastCommonNodeParent(p1 , p8 , p7);//p8和p7的最近公共祖先 if(p) cout<<"最近的公共祖先是p"<<p->m_nValue<<endl; else cout<<"不存在公共祖先"<<endl; TreeNode *q; q = findLCA(p1 , p8 , p7);//p8和p7的最近公共祖先 if(q) cout<<"最近的公共祖先是p"<<q->m_nValue<<endl; else cout<<"不存在公共祖先"<<endl; }

findLCA參考:http://www.acmerblog.com/lca-lowest-common-ancestor-5574.html

尋找二叉樹中的最低公共祖先結點----LCA(Lowest Common Ancestor )問題(遞歸)