LeetCode - 236. 二叉树的最近公共祖先

270 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。


原题:236. 二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

image.png

如上图,5 和 1 的最近公共祖先是 3,6 和 4 的最近公公祖先是 5。

解题思路:

以下解题思路以上图中的二叉树为例。首先,跟节点一定是任何两个元素的公共祖先,但不一定是最近公共祖先,或者可以说是「最远公共祖先」。此时,有一下三种情况:

  • 两个节点分别在跟节点的左右子树,那么跟节点就是最近公共祖先。
  • 两个节点都在跟节点的左子树,那么,跟节点的左子节点也是两个节点的公共祖先(不一定是最近公共祖先)
  • 两个节点都在跟节点的右子树,那么,跟节点的右子节点也是两个节点的公共祖先(不一定是最近公共祖先)

因此,我们可以这样找他们的最近公共祖先(两个节点分别是 p 和 q):

  1. 如果 p 和 q 任何一个节点和 root 是同一个节点,那么最近公共祖先就是 root
  2. 分别在左子树和又子树找两个节点
  3. 如果他们都在左子树,那么在左子树寻找他们的最近公共祖先
  4. 如果他们都在右子树,则在右子树寻找他们的最近公共祖先
  5. 如果都不在,那么他们的最近公共祖先就是 root

因为从左右子树寻找他们的最近公共祖先和最初的问题相同,则可以通过递归调用。

最终代码:

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null ||root.val == p.val || root.val == q.val) {
            return root;
        }
        if (nodeInTree(root.left, p) && nodeInTree(root.left, q)) {
            return lowestCommonAncestor(root.left, p, q);
        }
        if (nodeInTree(root.right, p) && nodeInTree(root.right, q)) {
            return lowestCommonAncestor(root.right, p, q);
        }
        return root;
    }
    
    private boolean nodeInTree(TreeNode root, TreeNode n) {
        if (root == null) {
            return false;
        }
        if (root.val == n.val) {
            return true;
        }
        
        return nodeInTree(root.left, n) || nodeInTree(root.right, n);
    }
}

以上用到了两个递归方法,其实可以并做一个。

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null || root == p || root == q) {
            return root;
        }
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        if (left == null) return right;
        if (right == null) return left;
        return root;
    }
}

这个写法可以理解为,从两个节点向上找他们的父节点,直到找到第一个共同的父节点即时我们要找的结果。