面试题68-Ⅰ.二叉搜索树的最近公共祖先
最近公共祖先的定义:设节点 root 为节点 p、q 的某公共祖先,若其左子节点 root.left 和右子节点 root.right 都不是 p、q 的公共祖先,则称 root 是最近的公共祖先
根据以上定义,若 root 是 p、q 的最近公共祖先,则只可能为以下情况之一:
1、p 和 q 在 root 的子树中,且分列 root 的异侧(即分别在左、右子树中);
2、p = root,且 q 在 root 的左或右子树中;
3、q = root,且 p 在 root 的左或右子树中;
则判断 p、q 与 root 的子树关系为:
- 若 root.val < p.val,则 p 在 root 右子树中
- 若 root.val > p.val,则 p 在 root 左子树中
- 若 root.val = p.val,则 p 和 root 指向同一节点
迭代
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
while(root != null) {
//根节点值小于两者的值,则说明在右子树中
if(root.val < p.val && root.val < q.val) root = root.right;
//根节点值大于两者的值,则说明在左子树中
else if(root.val > p.val && root.val > q.val) root = root.left;
else break;
}
return root;
}
}
- 时间复杂度 O(N) : 其中 N 为二叉树节点数;每循环一轮排除一层,二叉搜索树的层数最小为 logN (满二叉树),最大为 N (退化为链表)。
- 空间复杂度 O(1) : 使用常数大小的额外空间。
递归
class Solution {
//判断当前节点是否为p、q节点的共同祖先节点
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null) return root;
//小于两个节点,则说明一定存在右子节点中
if(root.val < q.val && root.val < p.val)
return lowestCommonAncestor(root.right, p, q);
else if(root.val > q.val && root.val > p.val)
return lowestCommonAncestor(root.left, p, q);
return root;
}
}
- 时间复杂度 O(N) : 其中 N 为二叉树节点数;每循环一轮排除一层,二叉搜索树的层数最小为 logN (满二叉树),最大为 N (退化为链表)。
- 空间复杂度 O(N) : 最差情况下,即树退化为链表时,递归深度达到树的层数 N 。
————————————————————————————————————————
面试题68-Ⅱ.二叉树的最近公共祖先
1、如果当前根为 null,或者当前根为任意目标节点,递归结束,开始回溯
2、分别向左子树和右子树查询两个目标节点是否存在
3、若都没有查到,则表示当前树中,不存在目标节点
4、若其中一颗子树没有查到,则公共祖先为另一颗子树
5、若都查询到了,则目标节点在当前 root 的两侧,即:当前 root 为最近公共祖先
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null) return null;
if(root = p || root == q) return root;
//分别向左子树和右子树查询两个目标节点是否存在
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
//若都没有查到,则表示当前树中,不存在目标节点
if(left == null && right == null) return null;
//若其中一颗子树没有查到,则公共祖先为另一颗子树
if(left == null) return rigth;
if(right == null) return left;
//若都查询到了,则目标节点在当前 root 的两侧,即:当前 root 为最近公共祖先
return root;
}
}
- 时间复杂度 O(N) : 其中 N 为二叉树节点数;最差情况下,需要递归遍历树的所有节点。
- 空间复杂度 O(N) : 最差情况下,递归深度达到 N ,系统使用 O(N) 大小的额外空间。