235.二叉搜索树的最近公共祖先
题目
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 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, q 位于哪个子树中。
- 如果 p, q 都小于父节点,最近公共祖先一定在左子树,继续递归左子树;
- 如果 p, q 都大于父节点,最近公共最先一定在右子树,继续递归右子树;
- 递归终止条件:p, q 一个大于父节点,另一个小于父节点。证明位于左右两边,此时可知最近公共祖先就是当前父节点,返回父节点。
代码
1 | public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { |
时间复杂度:O(N) 遍历整棵树;
空间复杂度:O(N) 递归占用栈空间。
除了使用递归的写法,也可以改写为 while
循环的写法:
1 | public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { |
时间复杂度:O(N) 遍历整棵树;
空间复杂度:O(1) 没有其他空间占用。
236.二叉树的最近公共祖先
题目
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
示例 1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
示例 2:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。
说明:
所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉树中。
解析
该题给的是一棵二叉树,我们的思路是递归遍历整棵树:
- 递归终止条件:如果 root 节点是空,或者等于 p 或者 q,直接返回 root 节点;
- 递归左子树:在左子树中查找 p 或 q,如果能找到就返回 p 或 q,找不到就返回 null;
- 递归右子树:在右子树中查找 p 或 q,如果找到就返回 p 或 q,找不到就返回 null;
- 返回值判断:
- 如果左子树和右子树都有返回值,证明两个节点分别位于左右两棵树,公共祖先为当前节点;
- 如果左子树中找不到 p 和 q,证明两个节点都在右子树,公共祖先在右子树;
- 如果右子树中找不到 p 和 q,证明两个节点都在左子树,公共祖先在左子树;
- 如果两个子树都找不到,证明找不到 p 和 q,返回 null。
代码
1 | public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { |
时间复杂度:O(N) 遍历整棵树
空间复杂度:O(N) 递归占用栈空间
本文首发于我的个人博客 https://chaohang.top
作者张小超
转载请注明出处
欢迎关注我的微信公众号 【超超不会飞】,获取第一时间的更新。