[未完成][基础算法/讨论]关于二叉树最小公共祖先(LCA)
设二叉树节点数为n,寻求m对的最小公共祖先(保证点值存在且唯一)
一、对于只寻求一对的最小公共祖先(即寻求数m = 1):
这种可以直接采用简单的O(n)算法,设公共祖先为V,两点分别为O1与O2,规律如下:
- 若V为O1与O2中一点,则另一个点处在V的其中一个左右子树中
- 若V不为O1与O2,则O1与O2分布在V的两个不同子树中,且O1与O2分布在非最小公共祖先的同一个子树
因此据此写出代码:
- 若节点为空,返回 nullptr;
- 若节点为O1或者O2,返回该值 Chird_Val;
- 递归遍历左右子树,并分别记录左右返回值 Chird_Val;
- 若左右子树都有非 nullptr返回值 Chird_Val,则返回该点值 Root_Val(说明该点为最小公共祖先);
- 若只有一个有非 nullptr返回值 Chird_Val,则返回该返回值 Chird_Val;
- 若左右子树都为 nullptr返回值,则返回 nullptr;
二、对于多寻求的最小公共祖先
这种如果采用上面的算法,则很明显时间复杂程度为O(mn),不太高效,以下分享两种算法,分别是离线与在线操作
I. Tarjan 离线算法
该算法也可以操作非二叉树图,时间复杂程度为O(n+m)
需要维护一个并查集(各节点不小于1,并查集初始化father[x] = x)。
对于二叉树来讲,设目前点为u,u的儿子节点为v,与u有关的查询节点为w,tarjan算法具体规则如下
- for each(v): dfs(v)
- 使v与u融合(并查集,father[find(v)] = u,此时father[u] = u恒成立)
- for each(w)
- 若w被遍历过,则father[w]为u与w的最小公共祖先
证明:类似于一* 中的规律。