[Go版]算法通关村第八关黄金——寻找祖先问题(二叉树最难问题之一)

题目:二叉树的最近公共祖先

题目链接:LeetCode-236. 二叉树的最近公共祖先
在这里插入图片描述

解法一:从根节点从上到下递归遍历找

思路分析

在这里插入图片描述

  1. 如果p或者q就是root节点,则第一个公共父节点就是root,因为根据定义最近公共父节点可以是节点本身。(比如上图:p=3 q=8 或者 q=3 p=2)
  2. 如果递归到叶子节点了,但是还没有找到p或q,则直接返回nil,上层会再回溯判断的。
  3. 从根节点root往左右子树看,
    1. 如果p q在同一侧,则可以直接放弃另一侧的递归查找,直接从同侧递归下去即可。(比如上图:p=5 q=7 或者 p=0 q=8)
    2. 如果p q分布在两侧,则继续左右递归下去。(比如上图:p=5 q=0 或者 p=7 q=1)

复杂度:时间复杂度 O ( n ) O(n) O(n)、空间复杂度 O ( n ) O(n) O(n)

Go代码

 func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
     if root == nil || root == p || root == q {
         return root
     }
     if root.Left == nil && root.Right == nil {
         return nil
     }
     left := lowestCommonAncestor(root.Left, p, q)
     right := lowestCommonAncestor(root.Right, p, q)
     if left != nil && right != nil {
         return root
     }
     if left == nil {
         return right
     }
     return left
}

解法二:从p、q节点向根节点方向遍历找第一个公共父节点

思路分析

  1. 先遍历所有子节点,将其的父节点找到,放入map中存储,方便之后直接从任一节点定位其父节点。
  2. 从p节点开始找他的所有父节点,并放入到p的父节点map中存储。
  3. 从q节点开始判断他的父节点是否在p的父节点map中存在,不存在就继续下一个父节点找,这样找到的第一个存在于p父节点map中的节点就是p和q的公共父节点。
  4. 如果最后都没有找到,说明p或者q不在该树中。

复杂度:时间复杂度 O ( n ) O(n) O(n)、空间复杂度 O ( n ) O(n) O(n)

Go代码

 func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
    if root == nil || root == p || root == q {
        return root
    }
    parentMap := make(map[int]*TreeNode, 0)
    pParentMap := make(map[*TreeNode]bool, 0)
    // 把所有节点对应的父节点都找到
    var findParent func(*TreeNode)
    findParent = func(node *TreeNode) {
        if node.Left != nil {
            parentMap[node.Left.Val] = node
            findParent(node.Left)
        }
        if node.Right != nil {
            parentMap[node.Right.Val] = node
            findParent(node.Right)
        }
    }
    findParent(root)
    // 找到p的所有父节点
    for p != nil {
        pParentMap[p] = true
        p = parentMap[p.Val]
    }
    // 找到p和q的第一个公共父节点
    for q != nil {
        if pParentMap[q] {
            return q
        }
        q = parentMap[q.Val]
    }
    return nil
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值