一、题目描述
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。百度百科中最近公共祖先的定义为:对于有根树 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, 因为根据定义最近公共祖先节点可以为节点本身。
说明:
所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉搜索树中。
二、思路分析
注:思路分析中的一些内容和图片参考自力扣各位前辈的题解,感谢他们的无私奉献
思路
祖先的定义: 若节点 p p p 在节点 r o o t root root 的左(右)子树中,或 p = r o o t p = root p=root,则称 r o o t root root 是 p p p 的祖先
最近公共祖先的定义: 设节点 r o o t root root 为节点 p p p 和 q q q 的某公共祖先,若其左子节点 r o o t . l e f t root.left root.left 和右子节点 r o o t . r i g h t root.right root.right 都不是 p p p 和 q q q 的公共祖先,则称 r o o t root root 是最近的公共祖先。
根据以上定义,若 r o o t root root 是 p p p, q q q 的最近公共祖先,则只可能为以下情况之一:
p p p 和 q q q 在 r o o t root root 的子树中,且分列 r o o t root root 的异侧(即分别在左、右子树中)
p = r o o t p = root p=root,且 q q q 在 r o o t root root 的左或右子树中
q = r o o t q = root q=root,且 p p p 在 r o o t root root 的左或右子树中
本题给定了两个重要条件:①树为二叉搜索树②树的所有节点的值都是唯一的。根据以上条件,可方便地判断 p p p, q q q 与 r o o t root root 的子树关系,即:
若 r o o t . v a l < p . v a l root.val < p.val root.val<p.val,则 p p p 在 r o o t root root 右子树中
若 r o o t . v a l > p . v a l root.val > p.val root.val>p.val,则 p p p 在 r o o t root root 左子树中
若 r o o t . v a l = p . v a l root.val = p.val root.val=p.val,则 p p p 和 r o o t root root 指向同一节点
方法一:迭代
算法流程:
①循环搜索: 当节点root
为空时跳出;
----当p
,q
都在root
的右子树中,则遍历至root.right
----否则,当p
,q
都在root
的左子树中,则遍历至root.left
----否则,说明找到了最近公共祖先,跳出
②返回值:最近公共祖先root
案例分析:
复杂度分析:
时间复杂度 O ( N ) \rm{O(N)} O(N):其中N
为二叉树节点数,每循环一轮排除一层,二叉搜索树的层数最小为logN
(满二叉树),最大为N
(退化为链表)
空间复杂度 O ( 1 ) \rm{O(1)} O(1):使用常数大小的额外空间
方法二:递归
算法流程:
①递推工作:
----当p
,q
都在root
的右子树中,则开启递归root.right
并返回
----否则,当p
,q
都在root
的左子树中,则开启递归root.left
并返回
②返回值:最近公共祖先root
复杂度分析:
时间复杂度 O ( N ) \rm{O(N)} O(N):其中N
为二叉树节点数,每循环一轮排除一层,二叉搜索树的层数最小为logN
(满二叉树),最大为N
(退化为链表)
空间复杂度 O ( N ) \rm{O(N)} O(N):最差情况下,即树退化为链表时,递归深度达到树的层数N
三、整体代码
迭代算法整体代码如下
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
while(root){
if(p->val < root->val && q->val < root->val){
root = root->left;
}
else if(p->val > root->val && q->val > root->val){
root = root->right;
}
else{
break;
}
}
return root;
}
运行,测试通过
递归算法整体代码如下
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
if(p->val < root->val && q->val < root->val){
return lowestCommonAncestor(root->left, p, q);
}
if(p->val > root->val && q->val > root->val){
return lowestCommonAncestor(root->right, p, q);
}
return root;
}
运行,测试通过