給定一棵樹,同時給出樹中的兩個結點(n1和n2),求它們的最低公共祖先。也就是常見的lca(lowest common ancestor )問題。
看下面的圖就明白了:
方法一下面是乙個簡單的複雜度為 o(n) 的演算法,解決lca問題
1)找到從根到n1的路徑,並儲存在乙個向量或陣列中。
2)找到從根到n2的路徑,並儲存在乙個向量或陣列中。
3) 遍歷這兩條路徑,直到遇到乙個不同的節點,則前面的那個即為最低公共祖先.
下面的c++的程式實現
// o(n) 解決 lca
#include
#include
using namespace std;
//二叉樹節點
struct node
int key;
struct node *left, *right;
//公用函式,生成乙個節點
node * newnode(int k)
node *temp =new node;
temp->key = k;
temp->left = temp->right = null;
return temp;
//找到從root到 節點值為key的路徑,儲存在path中。沒有的話返回-1
bool findpath(node * root,vector &path,int key)else
ans = path1[i];
return ans;
return -1;
// driver program to test above functions
int main()
// 按照上面的圖來創建立樹
node * root = newnode(1);
root->left = newnode(2);
root->right = newnode(3);
root->left->left = newnode(4);
root->left->right = newnode(5);
root->right->left = newnode(6);
root->right->right = newnode(7);
cout <
cout <
cout <
cout <
return 0;
輸出:lca(4, 5) = 2
lca(4, 6) = 1
lca(3, 4) = 1
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在左子樹中,否則在右子樹。
/* 只用一次遍歷解決lca */
#include
using namespace std;
struct node
struct node *left, *right;
int key;
node* newnode(int key)
node *temp =new node;
temp->key = key;
temp->left = temp->right = null;
return temp;
// 返回n1和n2的 lca的指標
// 假設n1和n2都出現在樹中
struct node *findlca(struct node* root,int n1,int n2)
if (root == null)return null;
// 只要n1 或 n2 的任乙個匹配即可
// (注意:如果 乙個節點是另乙個祖先,則返回的是祖先節點。因為遞迴是要返回到祖先的 )
if (root->key == n1 || root->key == n2)
return root;
// 分別在左右子樹查詢
node *left_lca = findlca(root->left, n1, n2);
node *right_lca = findlca(root->right, n1, n2);
// 如果都返回非空指標 non-null, 則說明兩個節點分別出現了在兩個子樹中,則當前節點肯定為lca
if (left_lca && right_lca)return root;
// 如果乙個為空,在說明lca在另乙個子樹
return (left_lca != null)? left_lca: right_lca;
//測試
int main()
// 構造上面圖中的樹
node * root = newnode(1);
root->left = newnode(2);
root->right = newnode(3);
root->left->left = newnode(4);
root->left->right = newnode(5);
root->right->left = newnode(6);
root->right->right = newnode(7);
cout cout cout cout return 0;
時間複雜度為o(n),但是上面的方法還是有所侷限的,必須保證兩個要查詢的節點n1和n2都出現在樹中。如果n1不在樹中,則會返回n2為lca,理想答案應該為null。要解決這個問題,可以先查詢下 n1和n2是否出現在樹中,然後加幾個判斷即可。
二叉樹最近共同祖先
從鍵盤接收擴充套件先序序列,以二叉鍊錶作為儲存結構,建立二叉樹。求兩個不同結點ch1,ch2的最近共同祖先。第一行 擴充套件先序序列 第二行 ch1,ch2兩個不同結點值,用乙個空格間隔。abc de g f c fb include include include typedef struct n...
尋找二叉樹兩個結點的最低共同父節點
題目 二叉樹的結點的定義如下 struct treenode 輸入二叉樹中的兩個結點,輸出這兩個結點在數中最低的共同父結點。尋找二叉樹兩個結點的最低共同父節點 treenode findfirstcommonparentnode treenode proot,treenode pnodeone,tr...
編號滿二叉樹 尋找任意兩結點的最近共同祖先
這是第一篇 技術性 部落格,希望以後越寫越多越好咯,本科生的期許hhh 這道題運用的主要性質就是對於滿二叉樹任意結點編號i 其parent 若有 為 i 2 關鍵在於對演算法的優化 一開始只想把 寫出來,於是用了 math.h 的pow函式,意圖先算出兩個結點的level,然後根據level 的差值...