0. 题目来源
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree
1. 题目描述
-
问题:
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 -
最近公共祖先的定义:
“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。
例如:给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
- 示例1:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2 和节点 8 的最近公共祖先是 6 - 示例2:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。
2. 问题分析
做题分析题目非常重要,要理解清楚题目要表达的意思,以及题中出现定义的含义。
有两个注意点:
- 题目中二叉树为二叉搜索树,即左子树中所有节点的值一定小于根节点,右子树中所有节点的值一定大于根节点,所以在搜索的时候可以根据值的大小来选择在左子树或者右子树中搜索;
- 题目中出现了最近公共祖先的定义,结合图片,假如从根节点开始搜索,可以得到如下结论:
- 如果两个节点值都小于根节点,说明他们都在根节点的左子树上,我们往左子树上找
- 如果两个节点值都大于根节点,说明他们都在根节点的右子树上,我们往右子树上找
- 如果一个节点值大于根节点,一个节点值小于根节点,说明他们一个在根节点的左子树上一个在根节点的右子树上,那么此时根节点就是他们的最近公共祖先节点。
3. 代码实现
有了2中的思路,可以用递归和非递归两种方法实现,具体分析过程请参考。
- 非递归方法,即迭代搜索:
public class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// 先让p节点的值小于q,这样判断边界条件时就只用判断一个
if (p.val > q.val){
TreeNode temp = p;
p = q;
q = temp;
}
// 根节点不为空时才判断
while (root != null){
if (root.val < p.val) //此时,根节点值比最小的还要小,说明p和q都在右子树中
root = root.right;
else if (root.val > q.val)//此时,根节点值比最大的还要大,说明p和q都在左子树中
root = root.left;
else // 此时找到了公共祖先
break;;
}
return root;
}
}
提交结果:
2. 递归搜索:
public class Solution2 {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null)
return null;
// 先使得p的值小于q的值
if (p.val > q.val){
TreeNode temp = new TreeNode();
temp = p;
p = q;
q= temp;
}
TreeNode node = helper(root, p, q);
return node;
}
private TreeNode helper(TreeNode root, TreeNode p, TreeNode q){
if (root.val < p.val){ // 比最小的还要小,说明p和q都在右子树中
return helper(root.right,p,q);
}else if (root.val > q.val){ // 比最大的还要大,说明p和q都在左子树中
return helper(root,p,q);
}else
return root;
}
}
提交结果: