最近公共祖先

2021-08-04 16:43:02 字數 3267 閱讀 1192

下面是乙個簡單的複雜度為 o(n) 的演算法,解決lca問題

1)找到從根到n1的路徑,並儲存在乙個向量或陣列中。

2)找到從根到n2的路徑,並儲存在乙個向量或陣列中。

3)遍歷這兩條路徑,直到遇到乙個不同的節點,則前面的那個即為最低公共祖先.

下面的c++的程式實現

01// o(n) 解決 lca

02#include

03#include

04usingnamespacestd;

05

06//二叉樹節點

07structnode

08;

12//公用函式,生成乙個節點

13node * newnode(intk)

14

20//找到從root到 節點值為key的路徑,儲存在path中。沒有的話返回-1

21boolfindpath(node * root,vector<int> &path,intkey)

32

33intfindlca(node * root,intkey1,intkey2)else

43ans = path1[i];

44}

45returnans;

46}

47return-1;

48}

49

50// driver program to test above functions

51intmain()

52

輸出:

1lca(4, 5) = 2

2lca(4, 6) = 1

3lca(3, 4) = 1

4lca(2, 4) = 2

時間複雜度:o(n), 樹被遍歷了兩次,每次遍歷複雜度不超過n,然後比較路徑。

上面的方法雖然是o(n),但是操作依然繁瑣了一點,並且需要額外的空間來儲存路徑。其實可以只遍歷一次,利用遞迴的巧妙之處。學好二叉樹,其實就是學好遞迴。

從root開始遍歷,如果n1和n2中的任乙個和root匹配,那麼root就是lca。 如果都不匹配,則分別遞迴左、右子樹,如果有乙個 key(n1或n2)出現在左子樹,並且另乙個key(n1或n2)出現在右子樹,則root就是lca.  如果兩個key都出現在左子樹,則說明lca在左子樹中,否則在右子樹。

01/* 只用一次遍歷解決lca */

02#include

03usingnamespacestd;

04structnode

05;

09node* newnode(intkey)

10

16

17// 返回n1和n2的 lca的指標

18// 假設n1和n2都出現在樹中

19structnode *findlca(structnode* root,intn1,intn2)

20

35

36//測試

37intmain()

38

時間複雜度為o(n),但是上面的方法還是有所侷限的,必須保證兩個要查詢的節點n1和n2都出現在樹中。如果n1不在樹中,則會返回n2為lca,理想答案應該為null。要解決這個問題,可以先查詢下 n1和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,表示詢問...