力扣题目——235. 二叉搜索树的最近公共祖先

注:本文的代码实现使用的是 JS(JavaScript),为前端中想使用JS练习算法和数据结构的小伙伴提供解题思路。(

描述

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

最近公共祖先的定义为:“对于有根树 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 为不同节点且均存在于给定的二叉搜索树中。

解题思路

1. 两次遍历法

我们可以两个数组p_pathq_path分别记录从根节点到pq的路径,然后从两个路径中找到最后一个相同的节点即可。因此,只要找出最大的编号i,其满足:
p _ p a t h [ i ] = q _ p a t h [ i ] p\_path[i] = q\_path[i] p_path[i]=q_path[i]
由于题目给定的是搜索二叉树,可以利用其性质,优化搜索过程。

var lowestCommonAncestor = function(root, p, q) {
	// 查找路径函数,root是原始的树,node是需要查找的节点
    let find = (root, node) => {
    	// 定义路径数组
        let path = []
        while(root){
            path.push(root)
            // 根节点的值小于查找节点的值,则遍历右子树
            if(root.val < node.val) root = root.right
            // 根节点的值大于查找节点的值,则遍历左子树
            else if(root.val > node.val) root = root.left
            // 找到需要查找的节点,返回路径
            else return path
        }
    }
    let p_path = find(root, p)
    let q_path = find(root, q)
    // 定义祖先变量
    let ancestor = null
    // 只需要在最短的路径中查找即可
    let len = Math.min(p_path.length, q_path.length)
    // 比较两个路径,若节点相同,则将 ancestor 指向该节点
    for(let i = 0; i < len; i++)
    	// 只要节点相同,ancestor 就会更新,因此 ancestor 保存的是最后一次相同的节点
        if(p_path[i] === q_path[i]) ancestor = p_path[i]
    return ancestor
};
2. 一次遍历法

我们还可以简化上面的方法。

  • 若节点pq的值均大于当前根节点的值,说明节点pq的祖先一定在当前节点的右子树上
  • 若节点pq的值均小于当前根节点的值,说明节点pq的祖先一定在当前节点的左子树上
  • 如果当前节点的值不满足上述两条要求,那么说明当前节点就是「分岔点」,即最近公共祖先
var lowestCommonAncestor = function(root, p, q) {
    while(true){
        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 return root
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值