首页 > 试题广场 >

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

[编程题]二叉搜索树的最近公共祖先
  • 热度指数:80298 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
1.对于该题的最近的公共祖先定义:对于有根树T的两个节点p、q,最近公共祖先LCA(T,p,q)表示一个点x,满足x是p和q的祖先且x的深度尽可能大。在这里,一个节点也可以是它自己的祖先.
2.二叉搜索树是若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值; 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值
3.所有节点的值都是唯一的。
4.p、q 为不同节点且均存在于给定的二叉搜索树中。
数据范围:
3<=节点总数<=10000
0<=节点值<=10000

如果给定以下搜索二叉树: {7,1,12,0,4,11,14,#,#,3,5},如下图:


示例1

输入

{7,1,12,0,4,11,14,#,#,3,5},1,12

输出

7

说明

节点1 和 节点12的最近公共祖先是7   
示例2

输入

{7,1,12,0,4,11,14,#,#,3,5},12,11

输出

12

说明

因为一个节点也可以是它自己的祖先.所以输出12   

说明:本题目包含复杂数据结构TreeNode,点此查看相关信息
超简单思路:
    // 算法思路
    /**
     * 将元素按升序进行排序 获取升序数组
     * 根据二叉搜索树 + 最近公共祖先的特性,最近公共祖先一定在[node(p), node(q)]之间。故此通过P,q获取升序子区间
     * 最后遍历升序子区间[node(p), node(q)] 获取node节点树, 根据dfs算法 判断当前节点能否同时找到 p q 如果能 说明是最近公共祖先
    */
export function lowestCommonAncestor(root: TreeNode, p: number, q: number): number {
    // write code here
    // 算法思路
    /**
     * 将元素按升序进行排序 获取升序数组
     * 根据二叉搜索树 + 最近公共祖先的特性,最近公共祖先一定在[node(p), node(q)]之间。故此通过P,q获取升序子区间
     * 最后遍历升序子区间[node(p), node(q)] 获取node节点树, 根据dfs算法 判断当前节点能否同时找到 p q 如果能 说明是最近公共祖先
    */
    let array:Array<TreeNode> = []
    inorder(root, array)
    array = getSubArray(array, p, q)

    for(let node of array) {
        if (dfs(node, p) && dfs(node, q)) return node.val
    }
    return root.val
}

// 将元素按升序进行排序
const inorder = (root: TreeNode, array:Array<TreeNode>) => {
    if(root === null) return
    inorder(root.left, array)
    array.push(root)
    inorder(root.right, array)
}
// 锁定查找最近公共祖先的元素区间
const getSubArray = (array:Array<TreeNode>, p: number, q: number) => {
    let left = 0
    let right = array.length - 1
    for(let i = 0 ; i < array.length; i++) {
        if (array[i].val === p) left = i
        if (array[i].val === q) right = i
    }

    return array.splice(left, right)
}
// 通过dfs判断在节点数能否找到目标值
const dfs = (root: TreeNode, target:number) => {
    if(root === null) {
        return false
    } 
    if(root.val === target) {
        return true
    }
    return dfs(root.left, target) || dfs(root.right, target)
}


发表于 2023-06-30 00:44:27 回复(0)
空间复杂度 O(1)  Morris遍历
export function lowestCommonAncestor(root: TreeNode, p: number, q: number): number {
    // write code here
    let cur = root;
    let right;
    let res;
    let next;
    while (cur !== null) {
        if (cur.left !== null) {
            right = cur.left;
            while (right.right !== null && right.right !== cur) {
                right = right.right;
            }
            if (right.right === null) {
                right.right = cur;
                cur = cur.left;
                continue;
            } else {
                right.right = null;
            }
        } 
        //核心代码
        if (cur.val === Math.min(p, q) || cur === next) {
            res = cur;
            if (res === root) return root.val;
            next = cur;
            while (next.right !== null && (next.right.left === null || (next.right.left !== null && next.right.left.val > cur.val))) {
                next = next.right;
            }
            next = next.right;
        }
        if (cur.val === Math.max(p, q)){
            return res.val;
        }
        cur = cur.right;   
    }
}


发表于 2022-07-21 17:50:32 回复(0)