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

77 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第16天,点击查看活动详情

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

一、题目描述:

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

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]

image.png

示例 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 为不同节点且均存在于给定的二叉搜索树中。

来源:力扣(LeetCode) 链接:leetcode.cn/problems/lo… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二、思路分析:

  1. 这道题考察了什么思想?你的思路是什么?

    我们找两个节点最近公共祖先可以从以下这个思路入手:

    我们先求出从根节点到这两个节点的路径,然后再在路径中查找最近的公共祖先。

    如何知道根节点到这两个节点的路径呢?

    因为是二叉搜索树,所以我们从根节点出发,比较当前节点的Val值与目的节点的Val值,然后去寻找下一个节点。

  2. 做题的时候是不是一次通过的,遇到了什么问题,需要注意什么细节?

    不是一次通过的,刚开始我的解法是这样的:

    /**
     * Definition for a binary tree node.
     * type TreeNode struct {
     *     Val   int
     *     Left  *TreeNode
     *     Right *TreeNode
     * }
     */func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
        path1 := getPath(root,p)
        path2 := getPath(root,q)
    ​
        index := 0
        for i:=0;i<len(path1) && i<len(path2) && path1[i] == path2[i];i++{
            index = i
        }
        
        return path1[index]
    }
    ​
    func getPath(root, node *TreeNode) ( path []*TreeNode ) {
        path = append(path,root)
        for root != nil {
            if root.Val > node.Val{
                root = root.Left
                path = append(path,root)
            }else{
                root = root.Right
                path = append(path,root)
            }
            if root == node{
                break
            }
        }
        return 
    }
    ​
    

    这样就会有一些问题,比如:

    [2,null,3]
    2
    3
    

    到2的路径就会执行else语句块,然后往右边走。

    最后路径就会变成: 2 3

    到3的路径也会变成 2 3

    这样就会导致lowestCommonAncestor执行的结果是3,而不是应当的2。

  3. 有几种解法,哪种解法时间复杂度最低,哪种解法空间复杂度最低,最优解法是什么?其他人的题解是什么,谁的效率更好一些?用不同语言实现的话,哪个语言速度最快?

image.png

    func lowestCommonAncestor(root, p, q *TreeNode) (ancestor *TreeNode) {
        ancestor = root
        for {
            if p.Val < ancestor.Val && q.Val < ancestor.Val {
                ancestor = ancestor.Left
            } else if p.Val > ancestor.Val && q.Val > ancestor.Val {
                ancestor = ancestor.Right
            } else {
                return
            }
        }
    }
    ​
    作者:LeetCode-Solution
    链接:https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/solution/er-cha-sou-suo-shu-de-zui-jin-gong-gong-zu-xian-26/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

三、AC 代码:

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val   int
 *     Left  *TreeNode
 *     Right *TreeNode
 * }
 */
​
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
    path1 := getPath(root,p)
    path2 := getPath(root,q)
​
    index := 0
    // fmt.Println(path1,path2)
    for i:=0;i<len(path1) && i<len(path2) && path1[i] == path2[i];i++{
        // fmt.Println(path1[i].Val,path2[i].Val)
        index = i
    }
    
    return path1[index]
}
​
func getPath(root, node *TreeNode) ( path []*TreeNode ) {
    path = append(path,root)
    for root != node {
        if root.Val > node.Val{
            root = root.Left
            path = append(path,root)
        }else{
            root = root.Right
            path = append(path,root)
        }
    }
    return 
}
​

四、总结:

我的两次遍历法时间复杂度和空间复杂度都为O(n),而一次遍历的时间复杂度是O(n),空间复杂度为O(1)。

模板来源:

作者:掘金酱

链接:juejin.cn/post/706970…

来源:稀土掘金

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。