下面是乙個簡單的複雜度為 o(n) 的演算法,解決lca問題
1)找到從根到n1的路徑,並儲存在乙個向量或陣列中。
2)找到從根到n2的路徑,並儲存在乙個向量或陣列中。
3)遍歷這兩條路徑,直到遇到乙個不同的節點,則前面的那個即為最低公共祖先.
下面的c++的程式實現
01
// o(n) 解決 lca
02
#include
03
#include
04
using
namespace
std;
05
06
//二叉樹節點
07
struct
node
08
;
12
//公用函式,生成乙個節點
13
node * newnode(
int
k)
14
20
//找到從root到 節點值為key的路徑,儲存在path中。沒有的話返回-1
21
bool
findpath(node * root,vector<
int
> &path,
int
key)
32
33
int
findlca(node * root,
int
key1,
int
key2)
else
43
ans = path1[i];
44
}
45
return
ans;
46
}
47
return
-1;
48
}
49
50
// driver program to test above functions
51
int
main()
52
輸出:
1
lca(4, 5) = 2
2
lca(4, 6) = 1
3
lca(3, 4) = 1
4
lca(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
03
using
namespace
std;
04
struct
node
05
;
09
node* newnode(
int
key)
10
16
17
// 返回n1和n2的 lca的指標
18
// 假設n1和n2都出現在樹中
19
struct
node *findlca(
struct
node* root,
int
n1,
int
n2)
20
35
36
//測試
37
int
main()
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,表示詢問...