尋找二叉樹兩個節點的最低公共祖先

從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是否出如今樹中,而後加幾個判斷便可。測試

相關文章
相關標籤/搜索