二叉樹結點的定義如下:
[cpp]view plain
copy
struct
node ;
給定二叉樹中的兩個結點,輸出這兩個結點的最低公共祖先結點(lca)。注意,該二叉樹不一定是二叉搜尋樹。
比如給定的二叉樹如下所示,則可以知道結點1和5的最低公共祖先結點為5,結點4和5的最低公共祖先結點為5。
_______3______/ \
___5__ ___1__
/ \ / \
6 _2 0 8
/ \
7 4
我們可以從根結點出發,判斷當前結點的左右子樹是否包含這兩個結點。如果左子樹包含兩個結點,則它們的最低公共祖先結點也一定在左子樹中。如果右子樹包含兩個結點,則它們的最低公共祖先結點也一定在右子樹中。如果乙個結點在左子樹,而另乙個結點在右子樹中,則當前結點就是它們的最低公共祖先結點。根據該思路寫出**如下,注意這裡已經假定p和q是二叉樹中的結點。
[cpp]view plain
copy
/*查詢二叉樹中兩個結點最低公共祖先結點*/
struct
node* lca(
struct
node *root,
struct
node *p,
struct
node *q)
/*判斷root為根的樹是否包含結點p*/
bool
hasnode(
struct
node* root,
struct
node* p)
由於我們對每個結點都呼叫了hasnode函式,而該函式類似於遍歷二叉樹,複雜度為o(n),所以總的時間複雜度為o(n^2),我們期望找到乙個更好的方法。
由於自頂向下的方法需要重複遍歷結點,使用自底向上的方法可以避免這種情況。
自底向上遍歷結點,一旦遇到結點等於p或者q,則將其向上傳遞給它的父結點。父結點會判斷它的左右子樹是否都包含其中乙個結點,如果是,則父結點一定是這兩個節點p和q的lca,傳遞父結點到root。如果不是,我們向上傳遞其中的包含結點p或者q的子結點,或者null(如果子結點不包含任何乙個)。該方法時間複雜度為o(n)。
[cpp]view plain
copy
typedef
struct
node node;
node *lca(node *root, node *p, node *q)
還有乙個方法就是依次得到從根結點到結點p和q的路徑,找出它們路徑中的最後乙個公共結點即是它們的lca。該演算法在何海濤先生的部落格中有詳細描述,這裡就不贅述,詳見該方法複雜度也為o(n),不過需要額外的空間儲存路徑,當然第2種方法中遞迴也是需要棧空間的,不過整體來看第2種方法簡潔但是不是很好理解,而公共路徑法則更加易懂。
最低公共祖先
對於樹中兩個節點而言,最低公共祖先lca其實就是該節點左邊和右邊分別包含a,b兩個節點。只有a,b分別在其左右子樹中。首先判斷該節點是否非空,空返回null,表示既沒有a,有沒有b 如果該節點本身是a,或者b中的乙個則返回該節點 遞迴的判斷該節點的左右子樹,如果左右子樹都不是返回null,說明左右子...
Tree 最低公共祖先系列
原題目 在bst中的特殊形式使得假如出現了乙個數比其中乙個小,比另乙個大就是復合題意了。不可能出現還有另外的情況。public treenode lowestcommonancestor treenode node,treenode p,treenode q else if root.val p.v...
最低公共祖先問題 鍊錶 樹
兩個鍊錶的第乙個公共節點 可以利用兩個輔助棧實現,也 可以遍歷鍊錶兩次,求節點個數差,長的鍊錶先遍歷,然後同時開始遍歷,找到相同節點 struct listnode listnode firstpublicnode listnode phead1,listnode phead2 while pnod...