题目:236. 二叉树的最近公共祖先
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
难度:中等
实现语言:python
本题我提交了两种解法:迭代和递归,下面我细说
一、迭代
看到二叉搜索树第一反应中序遍历,所以一开始我准备先把中序遍历骨架子搭好再填写逻辑
具体来说实现方式是先找p, q中值较小的节点,然后沿着中序就可以顺利找到祖先和另一个值较大的节点
但开始写的时候实现的时候发现不对劲,二叉搜索树的搜索操作本身就不需要遍历,那我还在这里写中序遍历就显得很蠢,看来还是理解不到位啊
那么问题来了,找祖先如何实现,难道后序遍历思路先找指定节点后找祖先?
也许不需要,因为二叉搜索树有个特性就是父节点的值大小一定位于介于左右孩子之间 ,而且由于所有节点都遵循这个规则,所以最近共同祖先的值也一定是介于两个指定值之间的,否则两个指定值不会位于该节点的两侧,就不可能成为最近共同祖先了
那么就有个顺利成章的猜想:是不是只要找到位于指定节点之间的值就是最近共同祖先呢?
确实是的
这个点我在代码随想录也看到了,但代码随想录中只是举了个例子,我没有看到详细可靠的原因,也许是在b站视频里说了吧
这里我的理解是:二叉树中任意一个节点的所有到根节点为止的祖先可以连接成一条路径,同样的道理,题目中输入的指定节点也是
那么对于两个指定的节点来说,它们的祖先路径有没有可能存在多个交会点或多个重合部分呢?
我觉得不可能,因为包括二叉树在内树都是从根节点出发的放射状的数据结构
所以说对于两个指定节点来说,二者的祖先路径一定存在有且唯一的重合部分,即二者的共同祖先也组成一条路径
那么,最近共同祖先就是共同祖先路径的终点(越往后越近,最近一定是终点),只有终点两个指定节点的祖先路径才会分叉,才有可能位于两侧
所以,我觉得到这里就可以自信地写出以下逻辑:从根节点出发,利用二叉树的有序性沿着两个指定节点的共同祖先路径往下找,找到的第一个值介于二者之间的节点就是共同祖先路径的终点,也就是最近的共同祖先:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
# 让p q有大小有序,并把两个指定节点的值单独存起来,便于比大小
if p.val > q.val:
p, q = q, p
pval = p.val
qval = q.val
node = root
while True:
# 当前节点比小的指定节点值还小,说明两指定节点都是当前节点左孩子的后代
if qval < node.val:
node = node.left
# 当前节点比大的指定节点值还小,说明两指定节点都是当前节点右孩子的后代
elif pval > node.val:
node = node.right
else:
# 当前节点值介于二者之间,即为最近共同祖先
return node
时间复杂度:O(N)
空间复杂度:O(1)
二、递归
与代码随想录不同,我是先写出的迭代,后写出的递归
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if root.val > q.val and root.val > p.val:
return self.lowestCommonAncestor(root.left, p, q)
if root.val < q.val and root.val < p.val:
return self.lowestCommonAncestor(root.right, p, q)
return root
如果有大佬看见了我思路上的错误或代码不完善的地方,请帮助指出,刷题阶段非常希望能有快速提升