解题思路:
分析:
1.如果树的结构是带有parent的三叉链结构,一个节点就可以通过parent不断地向上找,直到parent为空,此时就会形成一条路径;这样就转换成了链表相交问题。
2.如果树的结构为二叉搜索树,那么我们从根开始找:
a. 如果子节点比根要小,我们递归到左子树中去找,
b. 如果子节点比根要大,我们递归到右子树中去找。
c. 如果子节点一个比根大,一个比根小,那么它就是最近公共祖先。
3. 普通二叉树结构,从根开始搜索,查找子节点的位置 :
a. 都在左树 ,递归到左树去找,
b. 都在右树,递归到右树去找,
c. 一个在左,一个在右,根就是最近公共祖先。
① 代码实现:
class Solution {
public:
bool Find(TreeNode* root , TreeNode* x)
{
if(root == nullptr)
return false;
if(root == x)
return true;
return Find(root->left , x) || Find(root->right , x);
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
{
if(root == p || root == q) //一个节点也可以是他自己的祖先
return root;
bool IspInleft , IspInright , IsqInleft , IsqInright ;
IspInleft = Find(root->left , p); //查找 p/q 在 root 的左子树还是右子树
IspInright = !IspInleft;
IsqInleft = Find(root->left , q);
IsqInright = !IsqInleft;
if(IspInleft && IsqInleft) //两个节点都在左子树 ,递归到左子树找
{
return lowestCommonAncestor(root->left , p ,q);
}
else if(IspInright && IsqInright) //两个节点都在右子树,递归到右子树找
{
return lowestCommonAncestor(root->right , p , q);
}
else //一个在左 , 一个在右 ,找到了
{
return root;
}
}
};
性能分析:
②代码实现:优化到O(N),存储父节点。这里我们利用stack记录一个节点从根节点到目标节点经过的路径,最坏情况是吧全部的节点都访问,即O(N)
class Solution {
public:
bool FindPath(TreeNode* root , TreeNode* x , stack<TreeNode*>& pt)//递归将p ,q的路径保存在栈中
{
if(root ==nullptr)
return false;
pt.push(root);
if(root == x) //找到了
return true;
if(FindPath(root->left , x ,pt)) //没有找到递归到左子树
return true;
if(FindPath(root->right , x ,pt)) //没有找到递归到右子树
return true;
//左右子树都没有找到x,说明root不是路径中的节点,pop掉
pt.pop();
return false;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
{
stack<TreeNode*> pPath,qPath;
FindPath(root , p , pPath); //将p的路径获取
FindPath(root , q , qPath); //将q的路径获取
stack<TreeNode*>* longPath = &pPath;
stack<TreeNode*>* shortPath = &qPath;
if(longPath->size() < shortPath->size()) //找到最长的路径
swap(longPath , shortPath);
while(longPath->size() > shortPath->size()) //使两个路径长度相同
longPath->pop();
while(longPath->top() != shortPath->top()) //第一个相同的节点就是公共祖先
{
longPath->pop();
shortPath->pop();
}
return longPath->top();
}
};
③DFS
代码实现:
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
{
if(root == nullptr || root == p || root == q)
return root;
TreeNode *left = lowestCommonAncestor(root->left, p, q);
TreeNode *right = lowestCommonAncestor(root->right, p, q);
if(left == nullptr && right == nullptr)
return nullptr; // 1.
if(left == nullptr)
return right; // 3.
if(right == nullptr)
return left; // 4.
return root; // 2. if(left != null and right != null)
}
};
作者:jyd
链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/solution/236-er-cha-shu-de-zui-jin-gong-gong-zu-xian-hou-xu/
来源:力扣(LeetCode)