题目

函数:
java
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
}
}
思路
-
定义递归函数的含义:
- 我们设计一个递归函数,比如
find(node, p, q)。 - 这个函数的任务不是直接返回最终答案,而是返回它在以
node为根的子树中的查找结果。 - 查找结果有三种可能:
a. 在这棵子树里找到了p。
b. 在这棵子树里找到了q。
c. 在这棵子树里同时找到了p和q(这意味着我们已经找到了LCA)。
d. 什么都没找到。
- 我们设计一个递归函数,比如
-
后序遍历的思考方式:
- 要判断当前节点
node和p,q的关系,我需要先知道我的左子树 和右子树的查找结果。这就是典型的"后序遍历"思维------先处理子节点,再处理父节点。
- 要判断当前节点
-
在当前节点
node做出决策:- 我向我的左子树
node.left发出询问:find(node.left, p, q),得到左边的查找结果left_result。 - 我向我的右子树
node.right发出询问:find(node.right, p, q),得到右边的查找结果right_result。 - 现在,我作为
node节点,手握left_result和right_result这两条信息,开始分析:- 情况A:左边找到了一个,右边也找到了一个 (
left_result找到了p,right_result找到了q,或者反之)。- 这意味着什么?
p和q分别位于我的两侧!那我node不就是它们相遇的第一个节点吗?我就是它们的最近公共祖先!问题解决,我就是答案。
- 这意味着什么?
- 情况B:左边找到了 p 或 q,但右边什么也没找到 。
- 左子树返回的结果
left_result其实就是它那边找到的LCA或者目标节点p或q,我只需要把这个结果继续向上传递给我的父节点就行。
- 左子树返回的结果
- 情况C:右边找到了,左边没找到 。
- 和情况B同理,我把
right_result向上汇报。
- 和情况B同理,我把
- 情况D:我自己 (
node) 就是p或者q。- 根据定义,一个节点可以是自己的祖先。那我就是我这棵子树里能找到的最高的目标节点。我直接把自己作为结果向上汇报,都不用再问我的子树了。
- 情况A:左边找到了一个,右边也找到了一个 (
- 我向我的左子树
代码
java
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null) return null;
if(root.val == p.val || root.val == q.val) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if(left!=null&&right!=null) return root;
else if(left!=null) return left;
else if(right!=null) return right;
else return null;
}
}