每日一題 71 樹中兩個結點的最低公共祖先

2021-06-17 21:46:28 字數 4805 閱讀 2372

題目:給出兩個結點a和b,求解這兩個結點的最低公共祖先(lca)

前提:為了更好的說明思路,這裡讓問題簡單化,假設樹是二叉樹且樹中只含有乙個a和乙個b。

舉例:條件(1)樹為二叉搜尋樹

思路:

如果樹為二叉搜尋樹且樹中必須包含給出的兩個元素,可以利用二叉搜尋樹的性質來做。

如果樹中不包含給出的兩個元素,輸出的結果會是錯誤的。

**:

struct btnode

;btnode* findlca(btnode* proot,int nfirst,int nsec)

else if (proot->m_nvalue < nfirst && proot->m_nvalue < nsec)

else

}return null;

}

條件(2)一般的二叉樹 + 有指向父親的指標

思路:規劃為兩個相交鍊錶求交集。

**:樹使用兄弟孩子鍊錶法儲存。

struct csnode

;int nodecount(csnode* pnode)

return nlen;

}csnode* lca(csnode*& pfnode,csnode*& psnode)

} else }

assert(psnode && pfnode);

while(pfnode != psnode)

assert(pfnode);

return pfnode;

}csnode* findlca(csnode* proot,int nfirst,int nsec,csnode*& pfnode,csnode*& psnode)

if (pfnode && psnode)

//比較值

if (proot->m_nvalue == nfirst)

if (proot->m_nvalue == nsec)

//遞迴

if (pfnode && psnode)

csnode* plcaleft = findlca(proot->m_pfirstchild,nfirst,nsec,pfnode,psnode);

csnode* plcaright = findlca(proot->m_pnextsibling,nfirst,nsec,pfnode,psnode);

return plcaleft == null ? plcaright : plcaleft;

}

條件(3)一般的二叉樹 + 自頂向下深度遍歷

方法一:深度遍歷二叉樹,且每到乙個結點,都檢查該節點是否包含兩個結點。

如果本節點包含a和b 且 其左右子樹都不包含a和b,則此節點為lca

如果本節點包含a和b 且 其某個子樹也包含a和b,則也深度遍歷該子樹。

**:

struct btnode  

; /*求解lca*/

btnode* findlca(btnode* proot,int nfirst,int nsec)

bool bisinclude = isinclude(proot,nfirst,nsec);

if (!bisinclude)

else

else if (!plefttmp && prighttmp)

else

}}

在上述**中,沒有給出判斷乙個結點是否包含a和b的**,這裡給出兩種方法來判斷乙個結點是否包含a和b

方法(1)深度遍歷,判斷結點是否包含a和b

缺點:每確定乙個結點是否包含a和b時,都需要一次深度遍歷二叉樹。

**:

/*判斷結點是否同時包含a和b*/

bool isinclude(btnode* proot,int nfirst,int nsec,bool& bisinfir,bool& bisinsec)

if (proot->m_nvalue == nfirst)

if (proot->m_nvalue == nsec)

if (bisinfir && bisinsec)

else

else

}}/*判斷結點是否同時包含a和b*/

bool isinclude(btnode* proot,int nfirst,int nsec)

方法(2)使用雜湊,判斷結點是否包含a和b。

我們可以為每乙個結點都維護乙個雜湊,來儲存以該節點為根的子樹包含的結點。

這樣一來,檢測某個結點是否包含a和b時,只需要去map檢測a和b是否存在即可。

缺點:需要為每乙個結點維護乙個雜湊,存在空間浪費。

**:

void createmap(btnode* proot,map>& mapele)

createmap(proot->m_pleft,mapele);

createmap(proot->m_pright,mapele);

mapmaptmp;

maptmp.insert(pair(proot->m_nvalue,proot->m_nvalue));

//把倆孩子包含的結點值也給它

map>::iterator itcur;

if (proot->m_pleft)

if (proot->m_pright)

//把該節點的map插入總map中

mapele[proot->m_nvalue] = maptmp;

}/*判斷結點是否同時包含a和b*/

bool isinclude(map>& mapele,btnode* proot,int nfirst,int nsec)

map>::iterator itcur;

itcur = mapele.find(proot->m_nvalue);

if (itcur == mapele.end())

else

//查詢nsec

it = itcur->second.find(nsec);

if (it == itcur->second.end())

return true;

}}

方法二:邊深度遍歷,變儲存路徑

**:

struct btnode  

;/*求解lca*/

void findlca(btnode* proot,int nfirst,int nsec,bool& bisfindfir,bool& bisfindsec,vector& varrpathfir,vector& varrpathsec)

if (bisfindfir && bisfindsec)

varrpathfir.push_back(proot);

varrpathsec.push_back(proot);

if (proot->m_nvalue == nfirst)

if (proot->m_nvalue == nsec)

findlca(proot->m_pleft,nfirst,nsec,bisfindfir,bisfindsec,varrpathfir,varrpathsec);

findlca(proot->m_pright,nfirst,nsec,bisfindfir,bisfindsec,varrpathfir,varrpathsec);

if (!bisfindfir)

if (!bisfindsec) }

/*求解lca*/

btnode* findlca(btnode* proot,int nfirst,int nsec)

return ncount == 0 ? null : varrpathfir[ncur - 1];

}

思路(4)一般的二叉樹+ 自底向上

方法:遞迴回溯時記錄是否包含a和b。

如果包含,則是lca

如果不包含,則把包含資訊網上傳。

**:

struct btnode  

;bool isincude(int nflag)

return false;

}/*求解lca*/

void findlca(btnode* proot,int nfirst,int nsec,btnode*& plca,btnode* pparent)

if (plca)//已經找到lca

//處理本節點

if (proot->m_nvalue == nfirst)

if (proot->m_nvalue == nsec)

if (isincude(proot->m_nflag))

//遞迴入口

findlca(proot->m_pleft,nfirst,nsec,plca,proot);

findlca(proot->m_pright,nfirst,nsec,plca,proot);

if (plca)//在子樹中已經找到lca,此時包含資訊不需要網上傳了

if (isincude(proot->m_nflag))//判斷該節點是否是lca

if (pparent)//上傳關鍵字資訊 }

btnode* findlca(btnode* proot,int nfirst,int nsec)

思路(5)dfs + 並查集(tarjan演算法)

思路(6)dfs + st演算法

樹中兩個結點的最低公共祖先

題目 輸入兩個樹結點,求它們的最低公共祖先 題目一 如果這個樹是二叉搜尋樹,二叉搜尋樹是排序過的,位於左子樹的結點都比父結點小,而位於右子樹的結點都比父結點大,我們只需要從樹的根結點開始和兩個輸入的結點比較,如果輸入兩個結點都比根結點小,那麼最低的共同父結點一定在當前結點的左子樹中,於是下一步遍歷當...

樹中兩個結點的最低公共祖先

在進行這個問題之前,我們需要考慮以下幾個問題 1 題目告訴我們是樹,但是沒有告訴我們是一棵怎樣的樹。這裡的樹可以分為三種結構。第一種 普通的二叉樹 第二種 結點中含有指向父親結點的指標 第三種 二叉搜尋樹。2 對於不同結構的樹,處理的方式是不一樣的,時間複雜度也是不一樣的,我們需要針對每種結構設計解...

樹中兩個結點的最低公共祖先

場景一 二叉搜尋樹bst 假設是二叉搜尋樹 二叉搜尋樹是乙個排序的二叉樹,左子樹的結點小於根結點,右子樹的結點大於根結點 故找到乙個結點,使其大於左子結點小於右子結點即可。public static treenode getlastcommonnode treenode proot,treenode...