題目:給出兩個結點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...