0%

236. 二叉树的最近公共祖先

1. 递归

递归到以当前root为根的子树中查找是否包含p或q节点。
因为包含与否分四种情况:都不包含,只含p,只含q,都包含。
因此只用简单的true/false是不容易表示的,因此可以考虑返回指针,分别返回:null, &p, &q, root。
时间O(n),空间O(n)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == nullptr)
return nullptr;

if (root->val == p->val || root->val == q->val)
return root;

TreeNode* leftTree = lowestCommonAncestor(root->left, p, q);
TreeNode* rightTree = lowestCommonAncestor(root->right, p, q);

if (leftTree == nullptr)
return rightTree;
else if (rightTree == nullptr)
return leftTree;
else
return root;
}
};

2. 迭代

使用hash表记录每个节点的parent,然后分别找p和q节点的parent一直到整棵树的root,在此过程中查找最近公共祖先。
这就相当于在两个数组中查找最接近开始位置的相等值的位置。

  • 一种方法是朴素查找,p每访问一层parent,q遍历所有层的parent,时间复杂度O(n^2)

  • 第二种方法是hash表同时记录该parent的层数,然后p和q从parent的同一层出发公式向上找LCA。

  • 第三种方法是使用另一个hash表记录是否访问,p首先遍历各层的parent并标记为true,q在向上查找过程中访问到为true的节点即为公共祖先。

时间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
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == nullptr)
return nullptr;

unordered_map<int, TreeNode*> parent;
unordered_map<int, bool> vis;
queue<TreeNode*> que;

parent[root->val] = nullptr;
que.push(root);
while (!que.empty()) {
root = que.front();
que.pop();
if (root->left != nullptr) {
que.push(root->left);
parent[root->left->val] = root;
}
if (root->right != nullptr) {
que.push(root->right);
parent[root->right->val] = root;
}
}

while (p != nullptr) {
vis[p->val] = true;
p = parent[p->val];
}
while (q != nullptr) {
if (vis[q->val])
break;
q = parent[q->val];
}

return q;
}
};