leetcode链接:二叉树的最近公共祖先
思路1:
依次遍历每一个结点,遍历到当前根结点,再继续递归找 p
是否存在左子树 q
是否存在右子树,若 p
在左子树 q
在右子树或者 q
在左子树 p
在右子树,说明当前 root
就是 q
p
的公共祖先,若当前结点找不到这种情况,则当前 root
转换为子问题 root->left
root->right
继续递归寻找。
1️⃣ 代码:
class Solution {
public:
bool subTreeFind (TreeNode* root , TreeNode* key) {
if (root == nullptr) {
return false;
}
if (root == key) {
return true;
}
return subTreeFind(root->left , key) || subTreeFind(root->right , key);
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == nullptr) {
return nullptr;
}
// 当前结点可能就是公共祖先
if (root == p || root == q) {
return root;
}
// 方法1
// 检查当前子树的左子树是否存在p且当前子树的右子树是否存在q
// 或者 当前子树的左子树是否存在q且当前子树的右子树是否存在p
// 时间复杂度 O(H * N) N个结点 每个结点都要找左子树和右子树
//
bool pInLeft = subTreeFind(root->left , p);
bool pInRight = !pInLeft; // 不在左子树则必在右子树
bool qInLeft = subTreeFind(root->left , q);
bool qInRight = !qInLeft; // 不在左子树则必在右子树
if (pInLeft && qInRight) { // p在左 q在右 当前节点就是他们的公共祖先
return root;
}
if (qInLeft && pInRight) {
return root;
}
// 根节点不存在 转换为子问题 找左子树和右子树
TreeNode * leftParent = lowestCommonAncestor(root->left , p , q);
if (leftParent)
return leftParent;
TreeNode* rightParent = lowestCommonAncestor(root->right , p , q);
if (rightParent)
return rightParent;
// 一定存在
return nullptr;
}
}
思路2:
使用两个栈分别存 p
q
的结点路径,假设 root = [3,5,1,6,2,0,8,null,null,7,4] , p = 5 , q = 4
,pStack = {3 , 5}
qStack = {3 , 5 , 2 , 4}
,存好路径之后转换为链表相交问题,让大的先走差距步,qStack = {3 , 5}
在依次比较是否相等,若不相等则继续都出栈继续比较,相等则返回即可。
ps:
并不用判断无公共祖先的情况,因为 p
q
都存在于二叉树中。
2️⃣ 代码:
class Solution {
public:
bool inorderSearchPath (TreeNode* root, TreeNode* key , stack<TreeNode*>& path) {
if (root == nullptr) {
return false;
}
path.push(root); // 入栈
if (root == key) {
return true;
}
if (inorderSearchPath(root->left , key , path)) {
return true;
}
if (inorderSearchPath(root->right , key , path)) {
return true;
}
// 来到这里 说明左右结点都不存在 说明当前父节点也不在路径之中
path.pop(); // 出栈
return false;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
stack<TreeNode*> pPath;
stack<TreeNode*> qPath;
inorderSearchPath(root , p , pPath);
inorderSearchPath(root , q , qPath);
// 链表相交
// 大的先走差距步
while (pPath.size() > qPath.size()) {
pPath.pop();
}
while (qPath.size() > pPath.size()) {
qPath.pop();
}
while (pPath.top() != qPath.top()) {
pPath.pop();
qPath.pop();
}
// 一定存在
return pPath.top();
}
}