原始题目:剑指 Offer 68 - II. 二叉树的最近公共祖先 (opens new window)
# 方法一:哈希表
如果能知道每个节点的父节点,那么就可以通过 , 向上追溯找到最近的共同的父节点。因为题目中的二叉树并没有 指针,所以需要使用哈希表来映射子节点到父节点的关系。
拿到子节点和父节点的映射关系后,从 开始往上访问父节点,并记录起来。然后再从 开始往上遍历父节点,如果碰到已访问的节点,那么这个节点就是最近公共父节点。
代码:
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    Map<TreeNode, TreeNode> parentMap = new HashMap<>();
    Set<TreeNode> visited = new HashSet<>();
    getParentMap(parentMap, root, null);
    while(p != null) {
        visited.add(p);
        p = parentMap.get(p);
    }
    while(q != null) {
        if(visited.contains(q)) {
            return q;
        }
        q = parentMap.get(q);
    }
    return null;
}
private void getParentMap(Map<TreeNode, TreeNode> map, TreeNode node, TreeNode parent) {
    if (node == null) {
        return;
    }
    map.put(node, parent);
    getParentMap(map, node.left, node);
    getParentMap(map, node.right, node);
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
复杂度分析
- 时间复杂度: 为二叉树的节点个数。最差情况下,树退化成 “^” 型链表 ,最近公共父节点为根节点。
 - 空间复杂度:最差情况下,需要存储所有的树节点。
 
# 方法二:深度优先搜索
后序遍历二叉树,定义 表示 x 节点的子树是否包含 p 或者 q。如果包含为 true,否则为 false。那么最近的公共祖先一定满足如下条件:
和 分别表示 x 的左右子节点。这个条件表示
- 如果  或者  分别散布在 x 的左节点或者子节点,那么  就是 , 的最近公共父节点。
- 比如 在 的左子树, 在 的右子树。
 
 -  或者  就是  节点本身,那么就看另一个节点是否在 x 的子树中
- 比如 本身就是 节点了,那么就看 是否在 的子树中。
 
 
因为是自底向上的遍历,所以找到的公共祖先的深度一定是最大的。
代码:
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    findSon(root, p, q);
    return this.ans;
}
/**
 * 判断 root 中是否包含 p 或者 q
 */
private boolean findSon(TreeNode root, TreeNode p, TreeNode q) {
    if(root == null) {
        return false;
    }
    boolean inLeft = findSon(root.left, p, q);
    boolean inRight = findSon(root.right, p, q);
    if((inLeft && inRight) ||
            ((root.val == p.val || root.val == q.val) && (inLeft || inRight))){
        this.ans = root;
    }
    return inLeft || inRight || (root.val == p.val) || (root.val == q.val);
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
复杂度分析
- 时间复杂度:其中, 为二叉树的节点数。二叉树的节点有且只会被访问一次,因此时间复杂度为 。
 - 空间复杂度:最差情况下,树退化成链表,需要 递归栈空间。
 
