点击:题目链接:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科:最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
思路
根据题意,我们可以直接想到数组的后序遍历的特点。先判断它的子节点,最后再判断根节点。
由于题目中节点可能分散在树的各个地方,所以我们要注意以下几个判断条件:
- 如果一棵子树的两个节点就是所给的节点,则该子树的根节点就是公共祖先
- 如果一棵子树的其中一个节点是,那就要继续要往上继续判断,同时要标记当前子树根节点是包含所要的节点。
- 如果子树的根节点和其子节点都是指定的节点,则该根节点也是公共祖先
代码
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
|
class Solution { public: TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { dfs(root, p, q); return ans; }
private: TreeNode* ans; bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) { if (root == nullptr) return false;
bool leftNode = dfs(root->left, p, q); bool rightNode = dfs(root->right, p, q);
if ((leftNode && rightNode) || ((root->val == p->val) || (root->val == q->val) && (leftNode || rightNode))) { ans = root; }
return ((leftNode || rightNode) || (root->val == p->val) || (root->val == q->val)); } };
|
复杂度
时间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
| class Solution { public: TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { Nodes[root->val] = nullptr; dfs(root);
while (p) { vis[p->val] = true; p = Nodes[p->val]; }
while (q) { if (vis[q->val]) return q; q = Nodes[q->val]; } return nullptr;
}
private: TreeNode* ans; map<int, TreeNode*> Nodes; map<int, bool> vis;
void dfs(TreeNode* root) { if (root->left) { Nodes[root->left->val] = root; dfs(root->left); }
if (root->right) { Nodes[root->right->val] = root; dfs(root->right); } } };
|
复杂度
时间 O(N), 空间用到2N,所以O(N)