二叉樹兩結點的最低公共父結點

題目:求二叉樹中任意兩個節點的最低公共父節點。

思路:
從根結點開始遍歷,判斷以當前結點爲根的樹中左右子樹是不是包含我們要找的兩個結點。如果兩個結點都出現在它的左子樹中,那最低的共同父結點必出現在它的左子樹中;如果兩個結點都出現在它的右子樹中,那最低的共同父結點也出現在它的右子樹中;如果兩個結點一個出現在左子樹中,一個出現在右子樹中,那當前的結點就是最低的共同父結點。

struct BinaryTreeNode {
    int value;
    BinaryTreeNode *left;
    BinaryTreeNode *right;
}

bool containsNode(BinaryTreeNode *root,BinaryTreeNode *node){
    if(root == node)
        return true;
    bool flag = false;
    if(!flag && root->left != NULL)
        flag = containsNode(root->left,node);
    if(!flag && root->right != NULL)
        flag = containsNode(root->right,node);
    return flag;

}

BinaryTreeNode *lastCommonParentNode(BinaryTreeNode *root,BinaryTreeNode *node1,BinaryTreeNode *node2){
    if(root == NULL || node1 == NULL || node2 == NULL){
        return NULL;
    }
    bool leftsubtreehasnode1 = false;
    bool leftsubtreethasnode2 = false;
    if(root->left != NULL){
        leftsubtreehasnode1 = containsNode(root->left,node1);
        leftsubtreehasnode2 = containsNode(root->left,node2);
    }
    if(leftsubtreehasnode1 && leftsubtreehasnode2){
        if(root->left == node1 || root->left == node2)
            return root;
        return lastCommonParentNode(root->left,node1,node2);
    }

    bool rightsubtreehasnode1 = false;
    bool rightsubtreehasnode2 = false;
    if(root->right != NULL){
        if(leftsubtreehasnode1){
            rightsubtreehasnode1 = containsNode(root->right,node1);
        }
        if(leftsubtreehasnode2){
            rightsubtreehasnode2 = containsNode(root->right,node2);
        }   
    }
    if(rightsubtreehasnode1 && rightsubtreehasnode2){
        if(root->right == node1 || root->right == node2)
            return root;
        return lastCommonParentNode(root->right,node1,node2);
    }
    if((leftsubtreehasnode1 && rightsubtreehasnode2)|| (leftsubtreethasnode2 && rightsubtreehasnode1)){
        return root;
    }
    return NULL;    
}

時間複雜度爲O(n^2),因爲要遍歷樹中節點兩遍,這顯然不是最優的。

此題的變種:若每個節點都存有指向父節點的指針,如何求二叉樹中任意兩節點的最低公共子節點。

思路:此時我們可以把問題轉化爲兩個單鏈表求第一個公共子節點。
這裏寫圖片描述

而對於求兩個單鏈表的第一個公共子節點則是我們比較熟悉的。

struct BinaryTreeNode {
    int value;
    BinaryTreeNode *left;
    BinaryTreeNode *right;
}

bool getNodePath(BinaryTreeNode *root,BinaryTreeNode *node,list<BinaryTreeNode*> &path){
    if(root == node)
        return true;
    path.push_back(root);
    bool found = false;
    if(root->left != NULL)
        found = getNodePath(root->left,node,path);
    if(!found && root->left != NULL)
        found = getNodePath(root->right,node,path);
    if(!found)
        path.pop_back();
    return found;       
}

BinaryTreeNode *LastCommonNode(const list<BinaryTreeNode*> &list1,const list<BinaryTreeNode*> &list2){
    list<BinaryTreeNode*> list1;
    list<BinaryTreeNode*> list2;

    list<BinaryTreeNode*>::const_iterator iter1 = list1.begin();
    list<BinaryTreeNode*>::const_iterator iter2 = list2.begin();
    BinaryTreeNode *lastcommonnode = NULL;
    while(iter1 != list1.end() && iter2 != list2.end()){
        if(*iter1 == *iter2)
            lastcommonnode = iter1;
        iter1++;
        iter2++;
    }
    return lastcommonnode;
}

BinaryTreeNode *getLastCommonNode(BinaryTreeNode *root,BinaryTreeNode *node1,BinaryTreeNode *node2){
    if(root == NULL || node1 == NULL || node2 == NULL)
        return NULL;
    list<BinaryTreeNode*> path1;
    getNodePath(root,node1,path1);

    list<BinaryTreeNode*> path2;
    getNodePath(root,node2,path2);

    return LastCommonNode(path1,path2);
}
發佈了66 篇原創文章 · 獲贊 17 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章