從root開始遍歷,若是n1和n2中的任一個和root匹配,那麼root就是LCA。 若是都不匹配,則分別遞歸左、右子樹,若是有一個 key(n1或n2)出如今左子樹,而且另外一個key(n1或n2)出如今右子樹,則root就是LCA. 若是兩個key都出如今左子樹,則說明LCA在左子樹中,不然在右子樹。ios
/* 只用一次遍歷解決LCA */ #include <iostream> 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 << "LCA(4, 5) = " << findLCA(root, 4, 5)->key; cout << "\nLCA(4, 6) = " << findLCA(root, 4, 6)->key; cout << "\nLCA(3, 4) = " << findLCA(root, 3, 4)->key; cout << "\nLCA(2, 4) = " << findLCA(root, 2, 4)->key; return 0; }
時間複雜度爲O(n),可是上面的方法仍是有所侷限的,必須保證兩個要查找的節點n1和n2都出如今樹中。若是n1不在樹中,則會返回n2爲LCA,理想答案應該爲NULL。要解決這個問題,能夠先查找下 n1和n2是否出如今樹中,而後加幾個判斷便可。測試