问题
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。也是leetcode的236题。公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。
解决方法
1.简单版
代码如下:
public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) {
HashMap<TreeNode, TreeNode> fatherMap = new HashMap<>();
fatherMap.put(root, root);
process(root, fatherMap);
HashSet<TreeNode> set = new HashSet<>();
TreeNode cur = p;
while (cur != fatherMap.get(cur)) {
set.add(cur);
cur = fatherMap.get(cur);
}
set.add(root);
while (!set.contains(q)) {
q = fatherMap.get(q);
}
return q;
}
private void process(TreeNode root, HashMap<TreeNode, TreeNode> fatherMap) {
if (root == null)
return;
fatherMap.put(root.left, root);
fatherMap.put(root.right, root);
process(root.left, fatherMap);
process(root.right, fatherMap);
}
也就是定义一个HashMap,直接把每个节点的父亲给存进去,头结点root的父亲是它本身。存完之手,得到一个FatherMap,里面有每个节点的父亲,此时我们可以再定义一个Set集合,把p节点以及p节点的所有祖先节点都存进去,然后再去找q节点以及q的祖先,看其是否在Set集合内,找到的第一个节点就是他们的最近公共祖先。
2.优化版
代码如下:
public TreeNode lowestCommonAncestor2(TreeNode root, TreeNode p, TreeNode q) {
//如果节点为空了,或者节点等于p或者q就返回该节点
//第一个root ==null 是判断到了最后节点。
//root == p 或者 root == q 则是情况1,
// 也就是当找到第一个p或者q的时候,他就可能是LCA,就返回自己
if (root == null || root == p || root == q)
return root;
TreeNode left = lowestCommonAncestor2(root.left, p, q);
TreeNode right = lowestCommonAncestor2(root.right, p, q);
//如果左孩子不等于null且右孩子也不等于null,则表示,
// p跟q就在他们的左右孩子里,那么这个root就是他们的LCA
if (left != null && right != null)
return root;
//这里会返回有p或者q的节点
return left != null ? left : right;
}
这里思考一下,二叉树最低公共子先问题,它只有两种情况,
1、p是q的LCA,或者q是p的LCA。
2、p 跟 q都不互为LCA,需要往上找才知道他们的LCA
每次只返回p或者q,如果该子树上不含p或q则返回null,然后在每个节点处都要进行判断,如果该节点的左右孩子都不为null,也就意味着他的左右孩子含有p和q才会不为null,这是这个节点就肯定是他们的祖先节点。如果该节点的左右孩子有为null的情况,则返回有p或者q的,也就是不为null的节点,或者返回null。