百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
题目一:这棵树是一颗二叉搜索树的情况
二叉搜索树的性质:二叉搜索树是排序的
从当前树的根节点开始和两个输入的节点进行比较:
- 如果当前节点的值比两个节点的值都大,那么最低的共同父节点一定在当前节点的左子树,于是下一步遍历当前节点的左子树节点
- 如果当前节点的值比两个节点的值都小,那么最低的共同父节点一定在当前节点的右子树,于是下一步遍历当前节点的右子树节点
- 这样,从树中从上到下找到的第一个在两个输入节点值之间的节点就是最低的公共祖先
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if( (root->val > p->val) && (root->val > q->val))
return lowestCommonAncestor(root->left, p, q);
else if((root->val < p->val) && (root->val < q->val))
return lowestCommonAncestor(root->right, p, q);
else
return root;
}
题目二:这棵树是一颗普通树的情况
思路一:用递归
三种情况:
1、p q 一个在左子树 一个在右子树 那么当前节点即是最近公共祖先
2、p q 都在左子树
3、p q 都在右子树
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == nullptr) return nullptr;
if(root == p || root == q) return root;
//判断p q 是否在左 右子树中
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
//p q 一个在左子树 一个在右子树 返回他俩的根节点
if(left != nullptr && right != nullptr) {
return root;
}
//右子树里面没有p q
if(left != nullptr) {
return left;
}
//左子树没有p q
if(right != nullptr) {
return right;
}
//左 右子树都返回null
return nullptr;
}
};
思路二:剑指offer思路
- 找到从 root 到 p 的路径,以及从 root 到 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 || !p || !q || p ==root || q == root) {
return root;
}
vector<TreeNode*> pPath;
vector<TreeNode*> qPath;
getNodePath(root, p, pPath); // 找到从 root 到 p 的路径
getNodePath(root, q, qPath); // 找到从 root 到 q 的路径
return getlowestCommonAncestor(pPath, qPath); // 返回两条路径上最后一个相同的节点
}
void getNodePath(TreeNode* root, TreeNode* node, vector<TreeNode*>& path) { // 注意传引用
if (!root || !node) {
return;
}
TreeNode* temp = root, *prev = nullptr;
deque<TreeNode*> store;
while (temp || !store.empty()) {
while (temp) {
store.push_back(temp);
if (temp == node) { // 中
while (!store.empty()) {
// 如果 root 匹配到了 node,填充 path 并退出函数
TreeNode* t = store.front();
path.push_back(t);
store.pop_front();
}
return;
}
temp = temp -> left; // 左
}
temp = store.back();
if (!temp -> right || temp -> right == prev) {
// 如果 temp 没有右子节点,或者我们之前已经访问过其右子节点了
store.pop_back();
prev = temp;
temp = nullptr; // 这样就可以不进入上面那个 "while (temp)" 的子循环了
} else {
temp = temp -> right; // 右
}
}
}
TreeNode* getlowestCommonAncestor(vector<TreeNode*>& path1, vector<TreeNode*>& path2) { // 注意传引用
if (path1.empty() || path2.empty()) {
return nullptr;
}
int size = min(path1.size(), path2.size());
int i = 0;
for (; i < size; ++i) {
if (path1[i] == path2[i]) {
continue;
} else {
break; // 两条路径上的节点第一次不相同时,退出
}
}
return path1[i - 1]; // 返回两条路径上最后一次相同的节点
}
};