二叉树的最近公共祖先

题目描述

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

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

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

示例 1:

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

示例 2:

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

说明:

  • 所有节点的值都是唯一的。
  • p、q 为不同节点且均存在于给定的二叉树中。

题目链接

Leetcode

题目解答

解法一

存储父节点,遍历整棵树,使用哈希表记录所有子节点和父节点的对应关系,对于节点 p ,用 set 集合记录其父节点和所有祖先节点,对于节点 q ,依次向上查找父节点及祖先节点,如果节点在 set 集合中存在,该节点就是 pq 节点的最近公共祖先。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {

public Map<TreeNode,TreeNode> map = new HashMap<>();

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
dfs(root);
TreeNode pNode = p, qNode = q;
Set<TreeNode> set = new HashSet<>();
while(pNode != null) {
set.add(pNode);
pNode = map.get(pNode);
}
while(qNode != null) {
if (set.contains(qNode)) {
return qNode;
}
qNode = map.get(qNode);
}
return null;
}

public void dfs(TreeNode node) {
if (node == null) return;
if (node.left != null) {
map.put(node.left, node);
dfs(node.left);
}
if (node.right != null) {
map.put(node.right, node);
dfs(node.right);
}
}
}

执行用时:13 ms, 在所有 Java 提交中击败了8.56%的用户
内存消耗:38.7 MB, 在所有 Java 提交中击败了98.55%的用户

解法二

递归求解,对于树中指定的两个节点,它们最近的公共祖先要么是在左子树中,要么是在右子树中,如果左右子树都不包含公共祖先,那么最近的公共祖先就是根节点。节点本身也可以是自己的祖先,所以递归的跳出条件就是根节点为空或者根节点与任意一个指定节点相等,此时返回根节点即可,同时递归过程是自底向上的,可以保证递归找到的两个节点的公共祖先就是最近公共祖先。

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

1
2
3
4
5
6
7
8
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || p == root || q == root) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
return (left == null) ? right : ((right == null) ? left : root);
}
}

执行用时:7 ms, 在所有 Java 提交中击败了99.98%的用户
内存消耗:39.9 MB, 在所有 Java 提交中击败了50.89%的用户

-------------本文结束 感谢您的阅读-------------

文章对您有帮助,可以打赏一杯咖啡,鼓励我继续创作!