兩節點的最小公共祖先LCA


一、二叉搜索樹中兩節點的最小公共祖先:

    最初級的題目,在一顆二叉搜索樹中尋找兩節點的最小公共祖先。根據二叉搜索樹的特征,從根節點開始查找,若兩節點的val值都小於當前節點,則他們的最小公共祖先就去左子樹找,若兩節點的val值都大於當前節點,則他們的最小公共祖先就去右子樹找。直到一個節點的值小於當前節點,另一個節點的值大於當前節點,那么當前節點為最小公共祖先,即為找到了可以返回了。

c++代碼:

TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) 
{
        if(root == NULL)
            return root;
        if (p->val<root->val && q->val<root->val)
            return lowestCommonAncestor(root->left, p, q);
        else if(p->val>root->val && q->val>root->val)
            return lowestCommonAncestor(root->right, p, q);
        return root;       
}

 

二、二叉樹中兩節點的最小公共祖先:

    1、二叉樹有指向父節點的指針:當二叉樹中有指向父節點的指針時,可以倒過來看待這個問題,即為求兩個鏈表的公共節點。從當前節點開始往根節點數,記錄總共有多少個節點,記下數字。然后大數字的鏈表上先走幾步到數字一樣,再兩節點都一起往根節點走,第一個相同的節點即為最小公共子節點。參見求鏈表相交的部分

   2、二叉樹沒有指向父節點的指針:

    這是普通的二叉樹中求兩節點的最小公共祖先。

思路一:二叉樹中兩節點無外乎這樣幾種情況,兩節點p和q相等;p是q的子樹或子樹中的節點;q是p的子樹或子樹中的節點;q和p是兩支子樹,這時候可以遞歸找到他們的父節點繼續前面的思路;

C++代碼如下:

 bool ischild(TreeNode *pa, TreeNode *ch)
    {
        if (ch == pa || pa==nullptr)
            return false;
        if (pa->left==ch || pa->right==ch)
            return true;
        return ischild(pa->left, ch)||ischild(pa->right, ch);
    }
    TreeNode* find_pa(TreeNode* root, TreeNode*cur)
    {
        if (root->left == cur || root->right==cur)
            return root;
        if (ischild(root->left, cur))
            return find_pa(root->left, cur);
        else
            return find_pa(root->right, cur);
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (p==q)
            return q;
        if (ischild(p, q))
            return p;
        if (ischild(q,p))
            return q;
        TreeNode *p_pa=find_pa(root, p);
        TreeNode *q_pa=find_pa(root, q);
        if (ischild(p_pa, q_pa) || p_pa==q_pa)
            return p_pa;
        else if(ischild(q_pa, p_pa))
            return q_pa;
        else
            return lowestCommonAncestor(root, p_pa, q_pa);
    }

 

思路二:簡單直接一點。當root非空時,不斷從其左右子數搜索,①如果兩節點都在其左子樹,對其左子樹節點遞歸搜索;②如果兩節點都在其右子樹,對其右子樹節點遞歸搜索;③如果一個節點在左子樹一個節點在右子樹,則當前節點即為最小公共祖先。

C++代碼如下:

TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (root==NULL || root == p|| root==q)
            return root;
        if(p == q)
            return p;
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right,p,q);
        if (left!=NULL && right!=NULL)
            return root;
        else if(left == NULL)
            return right;
        return left;
    }

 

三、普通樹中兩節點的最小公共祖先:

    1、樹有指向父節點的指針:這種情況等同求鏈表的公共節點。同上參見求鏈表相交的部分

    2、樹沒有指向父節點的指針:此種情況我覺得可以參見上述第二種普通二叉樹求最小公共祖先(LCA)的方法,只是每次要在當前節點的每一個子樹搜索。然而現在記錄另外一種方法,參加劍指offer50題:可以用兩個輔助空間,在當前數中搜索兩個節點的路經並存下來。然后從根節點開始依次往后比較,記錄下最后一個相等的節點即為最小公共祖先。

C++代碼:

尋找路經:

 bool GetNodePath(TreeNode *pRoot, TreeNode *pNode, list<TreeNode*>&path){
 
   if (pRoot==pNode)
 
     return true;
 
   path.push_back(pRoot);
 
   bool found=false;
 
   vector<TreeNode*>::iterator i=pRoot->m_vChildren.begin();
 
   while(!found && i!=pRoot->m_vChildren.end())
 
   {  found = GetNodePath(*i, pNode, path); ++i}
 
   if(!found)
 
    path.pop_back();
 
   return found;

 }

 

在兩個路經中尋找最后的公共節點:

TreeNode *GetLastCommonNode(const list<TreeNode*>&path1,const list<TreeNode*>&path2 )
  
 {
 
  list<TreeNode*>::const_iterator iterator1=path1.begin();
 
  list<TreeNode*>::const_iterator iterator2=path2.begin();
 
  TreeNode* pLast=NULL;
 
   while(iterator1!=path1.end() && iterator2!=path2.end())
 
   {
 
     if (*iterator1 == *iterator2)//按照值在尋找,而非節點。。其實也是可以按照節點來尋找的

       pLast = *iterator1;  //這里按照我的理解 也應該直接賦值 沒有解引用 因為迭代器本身就是一個指針啊
 
     ++iterator1;++iterator2;
 
   }
 
   return pLast;
 
 }

 

尋找最小公共祖先:

TreeNode *GetLastCommonParent(TreeNode* pRoot, TreeNode* pNode1, TreeNode* pNode2)
 
 {
 
   if(pRoot==NULL || pRoot==pNode1 || pRoot==pNode2) return pRoot;
 
   if (pNode1 == pNode2)  return pNode1;

  List<TreeNode*>path1, path2;
 
   GetNodePath(pRoot,pNode1,path1);
 
   GetNodePath(pRoot,pNode2,path2);
 
   return GetLastCommonNode(path1,path2);
 
 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM