235. 二叉搜索树的最近公共祖先

递归

解题思路

  1. 对于二叉搜索树的最近祖先问题,其实要比普通二叉树公共祖先问题简单的多;不用使用回溯,二叉搜索树自带方向性,可以方便的从上向下查找目标区间,遇到目标区间内的节点,直接返回;

  2. 二叉搜索树性质决定了:

    • 如果 p.valq.val 都比 root.val 小,则 pq 肯定在 root 的左子树,递归左子树就行;
    • 如果 p.valq.val 都比 root.val 大,则递归右子树就行;
  3. 这三种情况,pq 的最近公共祖先都是 root

    • pq 分居 root 的左、右子树;
    • root 就是 pqp 的子树中;
    • root 就是 qpq 的子树中;

复杂度

  1. 时间复杂度:O(N),其中 N 为二叉树节点数;每循环一轮排除一层,二叉搜索树的层数最小为 log⁡N (满二叉树),最大为 N (退化为链表);

  2. 空间复杂度:O(N),最差情况下,即树退化为链表时,递归深度达到树的层数 N;

代码实现

var lowestCommonAncestor = function (root, p, q) {
    //  p.val 和 q.val 都比 root.val 小,则 p、q 在 root 的左子树
    if (p.val < root.val && q.val < root.val) {
        return lowestCommonAncestor(root.left, p, q);
    }

    //  p.val 和 q.val 都比 root.val 大,则 p、q 在 root 的右子树
    if (p.val > root.val && q.val > root.val) {
        return lowestCommonAncestor(root.right, p, q);
    }

    // root 是 p 或者 q
    return root;
}

迭代

解题思路

  1. 开启 while 循环,当 rootnull 时就结束:

    • 如果 p.valq.val 都小于 root.val ,它们都在 root 的左子树,root = root.left 向左寻找;
    • 如果 p.valq.val 都大于 root.val ,它们都在 root 的右子树,root = root.right 向右寻找;
    • 否则当前的 root 就是最近公共祖先,结束遍历;
  2. 返回 root ,即 break 时的 root 节点就是最近公共祖先;

复杂度

  1. 时间复杂度:O(N),其中 N 为二叉树节点数;每循环一轮排除一层,二叉搜索树的层数最小为 log⁡N (满二叉树),最大为 N (退化为链表);

  2. 空间复杂度:O(1)

代码实现

var lowestCommonAncestor = function (root, p, q) {
    while (root) {
        if (p.val < root.val && q.val < root.val) {
            // 1. 如果 p.val、q.val 都小于 root.val ,它们都在 root 的左子树,向左寻找
            root = root.left;
        } else if (p.val > root.val && q.val > root.val) {
            // 2. 如果 p.val、q.val 都大于 root.val ,它们都在 root 的右子树,向左寻找
            root = root.right;
        } else {
            // 3. 找到了公共祖先节点,直接退出
            break;
        }
    }

    return root;
}
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 递归
    1. 1.1. 解题思路
    2. 1.2. 复杂度
    3. 1.3. 代码实现
  2. 2. 迭代
    1. 2.1. 解题思路
    2. 2.2. 复杂度
    3. 2.3. 代码实现