题面
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree
题目分析
一开始想用并查集,然而发现递归挺好使的
注意到两个条件可以更新返回值且唯一:
- 某个节点左右两边都存在一个我们我找的p/q节点其中的一个,那么这个节点就是根节点,即我们要求的节点。因为树中没有相同val的节点所以可以这样使用而不用区分。
- 目标节点是其中另一个目标节点的最近公共祖先,这种情况下需要判断自己的值和遍历左右子树中是否有我们要寻找的p/q节点。
当然还有其他想法,我最初的想法是这样的:
首先树根节点肯定是所有节点的祖先,那么就先将ans置为root,然后判断根节点的左节点或者右节点是否能够更新为答案,即在左子树中是否有p\q节点,如果有则继续遍历左节点的左右节点,如果没有查看右子树中是否有p/q节点,如果有则继续更新答案。这样的话时间会远远超过上述的递归方法,因为这样的解法粗略的估计为O(N^2),而上述方法为O(N)
AC代码
第二种解法:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
TreeNode* ans;
bool flag1;
bool flag2;
public:
bool recursive(TreeNode* root, TreeNode* p, TreeNode* q) {
if(!root)
return false;
if(root->val == p->val) flag1 = true;
if(root->val == q->val) flag2 = true;
return (flag1 && flag2) || recursive(root->left, p, q) || recursive(root->right, p, q);
}
void getAns(TreeNode* root, TreeNode* p, TreeNode* q) {
flag1 = flag2 = false;
bool f1 = recursive(root->left, p, q);
flag1 = flag2 = false;
bool f2 = recursive(root->right, p, q);
if(f1)
getAns(root->left, p, q);
else if(f2)
getAns(root->right, p, q);
else {
ans = root;
}
return;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
ans = root;
getAns(root, p, q);
return ans;
}
};
第二种解法(官方解法)
class Solution {
public:
TreeNode* ans;
bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == nullptr) return false;
bool lson = dfs(root->left, p, q);
bool rson = dfs(root->right, p, q);
if ((lson && rson) || ((root->val == p->val || root->val == q->val) && (lson || rson))) {
ans = root;
}
return lson || rson || (root->val == p->val || root->val == q->val);
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
dfs(root, p, q);
return ans;
}
};
本人水平有限,如有任何错误,恳请大家指正,不要误导他人…
错误反馈: 1004183196@qq.com