First Common Ancestor:设计一个算法,查找树中两个节点的最近公共祖先节点。
如果是二叉搜索树,可以修改查找操作,看看两个节点在哪个节点进行分支,该节点就是最近公共祖先。
第1
种方法要使用父指针。如果每个节点有链接到父节点的指针,则可以通过父指针一直向上回溯,直到遇到相交节点,类似于找两个链表的交点,算法复杂度和更深的节点相关,但是力扣上没有父指针。
第2
种方法也需要父指针。在回溯到p
的父节点时,为了确定该节点是否是最近公共祖先,需要在p
的兄弟节点中查找q
,算法复杂度和最近公共祖先的子树大小相关。
第3
种不需要父指针。通过从根节点开始搜索p
和q
的所处的子树:
- 如果根节点就是
p
或者q
,则根节点就是最近公共祖先 - 如果都在左子树,则就在左子树中查找最近公共祖先
- 如果都在右子树,则就在右子树中查找最近公共祖先
- 否则根节点就是最近公共祖先
/**
* 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 {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(!exist(root, p) || !exist(root, q)) return nullptr;
return CommonAncestor(root, p, q);
}
private:
bool exist(TreeNode *root, TreeNode *n)
{
if(root == nullptr) return false;
else if(root == n) return true;
else return exist(root->left, n) || exist(root->right, n);
}
TreeNode* CommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q)
{
if(root == p || root == q) return root;
bool bPLeft = exist(root->left, p);
bool bQLeft = exist(root->left, q);
if(bPLeft && bQLeft){
return CommonAncestor(root->left, p, q);
}
else if(!bPLeft && !bQLeft){
return CommonAncestor(root->right, p, q);
}
else return root;
}
};
虽然会进行折半查找,但是再确定进入哪一半时另一半也需要遍历,所以算法复杂度为O(n)
。尽管时间复杂度已经很好了,但是exist()
会进行多次重复的遍历,如果每个节点只被访问一次就好了。对于一棵树,最近公共祖先可能是根节点,可能在左子树,也可能在右子树:
- 如果根节点就是
p
或者q
,则根节点就是最近公共祖先 - 否则在左子树中查找,可能找到最近公共祖先,也可能找到
p
或者q
,需要根据对右子树进行类似查找的情况区分这两种情况
/**
* 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 {
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 root;
else if(left != nullptr) return left;
else return right;
}
};