最近公共祖先

2021-05-25 07:41:35 字數 1156 閱讀 4908

題目:二叉樹的結點定義如下:

struct

treenode ;

輸入二叉樹中的兩個結點,輸出這兩個結點在數中最低的共同父結點。

分析:求數中兩個結點的最低共同結點是面試中經常出現的乙個問題。這個問題至少有兩個變種。

第一變種是二叉樹是一種特殊的二叉樹:查詢二叉樹。也就是樹是排序過的,位於左子樹上的結點都比父結點小,而位於右子樹的結點都比父結點大。我們只需要從根結點開始和兩個結點進行比較。如果當前結點的值比兩個結點都大,則最低的共同父結點一定在當前結點的左子樹中。如果當前結點的值比兩個結點都小,則最低的共同父結點一定在當前結點的右子樹中。

第二個變種是樹不一定是二叉樹,每個結點都有乙個指標指向它的父結點。於是我們可以從任何乙個結點出發,得到乙個到達樹根結點的單向鍊錶。因此這個問題轉換為兩個單向鍊錶的第乙個公共結點

現在我們回到這個問題本身。所謂共同的父結點,就是兩個結點都出現在這個結點的子樹中。因此我們可以定義一函式,來判斷乙個結點的子樹中是不是包含了另外乙個結點。這不是件很難的事,我們可以用遞迴的方法來實現:

我們可以從根結點開始,判斷以當前結點為根的樹中左右子樹是不是包含我們要找的兩個結點。如果兩個結點都出現在它的左子樹中,那最低的共同父結點也出現在它的左子樹中。如果兩個結點都出現在它的右子樹中,那最低的共同父結點也出現在它的右子樹中。如果兩個結點乙個出現在左子樹中,乙個出現在右子樹中,那當前的結點就是最低的共同父結點。基於這個思路,我們可以寫出如下**:

接著我們來分析一下這個方法的效率。函式

hasnode

的本質就是遍歷一棵樹,其時間複雜度是

o(n)(n

是樹中結點的數目)。由於我們根結點開始,要對每個結點呼叫函式

hasnode

。因此總的時間複雜度是

o(n2)

。我們仔細分析上述**,不難發現我們判斷以乙個結點為根的樹是否含有某個結點時,需要遍歷樹的每個結點。接下來我們判斷左子結點或者右結點為根的樹中是否含有要找結點,仍然需要遍歷。第二次遍歷的操作其實在前面的第一次遍歷都做過了。由於存在重複的遍歷,本方法在時間效率上肯定不是最好的。

前面我們提過如果結點中有乙個指向父結點的指標,我們可以把問題轉化為求兩個鍊錶的共同結點。現在我們可以想辦法得到這個鍊錶。我們在中分析過如何得到一條從根結點開始的路徑。我們在這裡稍作變化即可:

最近公共祖先 python 最近公共祖先

lca演算法樸素演算法 也就是我們所說的暴力演算法,大致的思路是從樹根開始,往下迭代,如果當前結點比兩個結點都小,那麼說明要從樹的右子樹中找 相反則從左子樹中查詢 直到找到乙個結點在當前結點的左邊,乙個在右邊,說明當前結點為最近公共祖先,如果乙個結點是另外乙個結點的祖先,那麼返回前面結點的父親結點即...

最近公共祖先 LCA 最近公共祖先

直接暴力搜尋參考 普通搜尋每次查詢都需要 樸素演算法是一層一層往上找,倍增的話直接預處理出乙個 具體做法是 維護乙個 的關係來線性求出這個陣列 int anc n 31 int dep n 記錄節點深度 void dfs int u,int parent for int i 0 i g u size...

最近公共祖先 最近公共祖先(LCA)

如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。輸入格式 第一行包含三個正整數n m s,分別表示樹的結點個數 詢問的個數和樹根結點的序號。接下來n 1行每行包含兩個正整數x y,表示x結點和y結點之間有一條直接連線的邊 資料保證可以構成樹 接下來m行每行包含兩個正整數a b,表示詢問...