介绍
二叉搜索树的公共祖先节点是指:对于给定的两个节点p、q,向上寻找离二者最近的公共节点。
public class Node<T extends Comparable<T>> {
T value;
Node<T> left;
Node<T> right;
public Node() {
}
public Node(T t) {
value = t; }
}
如图
- 2和4的公共祖先节点是3
- 2和6的公共祖先节点是5
- 6和7的公共祖先节点是7
需要注意的是,如果p是q的父节点,则二者的公共祖先节点是p,反之亦然。
解决办法
方式一
因为是搜索树,所以每个节点保存的值肯定不一样,所以我们可以遍历整棵树,记录从根节点到p的路径,根节点到q的路径
- 判断p、q是否满足父子关系,如果是,返回其中的父节点;
- 逆序的遍历一个路径的节点,同另一路径依次比较,若找到相同的节点,该节点即为公共祖先节点;
- 其他情况返回null
例如要判断4和7的公共祖先节点
4的路径:5 3 4
7的路径:5 7
首先判断4和7不是父子关系,然后开始遍历路径做比较
橙色块代表找到了第一个相同的节点,故4和7的公共祖先节点是5。
public class Node<T extends Comparable<T>> {
T value;
Node<T> left;
Node<T> right;
public Node() {
}
public Node(T t) {
value = t; }
}
//----------------------------------
public Node getLCA(Node<T> root, Node<T> p, Node<T> q) {
//如果具有父子关系,返回父节点
if(p.left == q || p.right == q) return p;
if(q.left == p || q.right == p) return q;
//查找路径
List<Node<T>> pPath = new ArrayList<>();
List<Node<T>> qPath = new ArrayList<>();
dfs(pPath, root, p);
dfs(qPath, root, q);
//比较路径节点,找到公共节点
return getLCA(pPath, qPath);
}
/**
* @path 记录从根节点到目标的路径节点
* @node 当前节点
* @aim 目标节点(p | q)
* @return 如果找到了目标节点,返回true
*/
private boolean dfs(List<Node<T>> path, Node<T> node, Node<T> aim) {
if(node == null) return false;
path.add(node);
if(node == aim) return true;
if(dfs(path, node.left, aim)) return true;
if(dfs(path, node.right, aim)) return true;
path.remove(path.size() - 1);
return false;
}
private Node getLCA(List<Node<T>> pPath, List<Node<T>> qPath) {
for(int i = pPath.size() - 2; i >=0; i--) {
Node node = pPath.get(i);
for(int j = qPath.size() - 2; j >= 0; j--) {
if(node == qPath.get(j)) return node;
}
}
return null;
}
这种方式最坏的情况下需要扫描整棵树,还需要另个集合存路径,之后还要逐个比较路径的节点值,时空花费都不小,我们来看第二种方式。
方式二
我们换一种思路,还是上面这棵树,从根节点出发,到达任意节点x,如果p、q的值都比x小,就走x的左子树;如果p、q的值都比x大,就走x的右子树。
拿上图为例,如果p、q都比x小,那么x一定是p、q的公共祖先节点,但x并不是最近的公共祖先节点,最近的公共祖先节点一定在x的左子树上。
第二种情况,如果p、q一个比x大,一个比x小呢?
如果是这样的话,那x恰好就是他俩的公共祖先节点了,稍加思考就会发现,x就是p、q的最近公共祖先节点。
第三种情况,p、q具有父子关系。
当x = p | q时,p、q既不在x的一边,也不在x的两侧,那直接返回x就好了。这种情况的处理方式和第二种情况处理方式一致,都是直接返回x。
public class Node<T extends Comparable<T>> {
T value;
Node<T> left;
Node<T> right;
public Node() {
}
public Node(T t) {
value = t; }
}
//----------------------------------
public Node getLCA(Node<T> root, Node<T> p, Node<T> q){
if(root == null) return null;
int pResult = root.value.compareTo(p.value);
int qResult = root.value.compareTo(q.value);
//p、q在x的同一侧
if(pResult > 0 && qResult > 0){
return getLCA(root.left, p, q);
}else if(pResult < 0 && qResult < 0){
return getLCA(root.right, p, q);
}else{
//p、q在x的两侧 || x = p | q
return root;
}
}