思路
- 如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。
- 因此,要实现自底向上的回溯查找,即先访问叶节点,再访问根节点。所以使用后序遍历。
终止条件
- 当前root为p或q,即找到了p或q,返回root。
- 到头了,遇到空节点,返回null。
单层逻辑
代码
- lowestCommonAncestor的含义:root及其子节点是否包含p或q?
- 如果包含,返回p或q
- 如果不包含,返回null
- 情况3、4中,qp同时在一边,返回的是pq中更靠上的那个。
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == p || root == q || root == null) {// root = null没找到,也要返回
return root;
}
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left != null && right != null) { //情况2.
return root;
} else if (left == null && right != null) { //情况3.
return right;
} else if (left != null && right == null) { //情况3.
return left;
} else { //left == null && right == null //情况1.
return null;
}
}
}
注意点
-
求最小公共祖先,需要从底向上遍历,那么二叉树,只能通过后序遍历(即:回溯)实现从低向上的遍历方式。
-
在回溯的过程中,必然要遍历整颗二叉树,即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值(也就是代码中的left和right)做逻辑判断。
-
要理解如果返回值left为空,right不为空为什么要返回right,为什么可以用返回right传给上一层结果。