「算法」二叉树的最近公共祖先 | 刷题打卡

855 阅读3分钟

本文正在参与掘金团队号上线活动,点击 查看大厂春招职位

一、题目描述:

原题链接 👉 236. 二叉树的最近公共祖先

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

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

示例 1:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3

示例 2:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。

示例 3:

输入:root = [1,2], p = 1, q = 2
输出:1

注意:

  • 树中节点数目在范围 [2, 105] 内。
  • -109 <= Node.val <= 109
  • 所有 Node.val 互不相同 。
  • p != q
  • p 和 q 均存在于给定的二叉树中。

二、思路分析:

**思路1:**递归

本题是求两个子节点的最近公共祖先节点。涉及到树的问题就先想到深度优先遍历和广度优先遍历。只要题目中指明是按照层级来处理的,就先考虑用广度优先遍历;其他场景特别是要转化成左右子树的场景可以考虑用深度优先遍历。此题用深度遍历。

  1. 确定递归终止条件:

    if (!root || root == p || root == q) return root
    

    如果root为空,返回root,不走下面的逻辑;root == p或者root == q表明当前节点root就是父节点,返回即可。

  2. 递归root.left和root.right,看这两个子树下是否有p,q的公共父节点。

    let left = lowestCommonAncestor(root.left, p, q)
    let right = lowestCommonAncestor(root.right, p, q)
    
    • 如果left和right都是null,说明p,q两个节点既不在左子树下,也不在右子树下,返回null即可
    • 如果left为null,right不为null,说明p,q两个节点在右子树下
    • 如果right为null,left不为null,说明p,q两个节点在左子树下
    • 如果left和right都不是null,说明root就是父节点

三、完整代码:

思路1:

var lowestCommonAncestor = function (root, p, q) {
  if (!root || root == p || root == q) return root
  let left = lowestCommonAncestor(root.left, p, q)
  let right = lowestCommonAncestor(root.right, p, q)
  if (left == null && right == null) return null
  if (left == null) return right
  if (right == null) return left
  return root
}

这道题还可以进行进一步的变形,是求公共祖先节点的值。只需要在上代码中小做修改就行。大家可以思考下。

复杂度分析:

  • 时间复杂度:O(N),其中 N 是二叉树的节点数。二叉树的所有节点有且只会被访问一次,因此时间复杂度为 O(N)。
  • 空间复杂度:O(N) ,其中 N 是二叉树的节点数。递归调用的栈深度取决于二叉树的高度,二叉树最坏情况下为一条链,此时高度为 N,因此空间复杂度为 O(N)。

四、总结:

二叉树的问题首先要想到深度优先遍历或广度优先遍历。查找二叉树的公共祖先节点使用到的是深度优先遍历。