BM37 二叉搜索树的最近公共祖
知识点树递归
描述
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。1.对于该题的最近的公共祖先定义:对于有根树T的两个节点p、q,最近公共祖先LCA(T,p,q)表示一个节点x,满足x是p和q的祖先且x的深度尽可能大。在这里,一个节点也可以是它自己的祖先.2.二叉搜索树是若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值; 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值3.所有节点的值都是唯一的。4.p、q 为不同节点且均存在于给定的二叉搜索树中。数据范围:3<=节点总数<=100000<=节点值<=10000如果给定以下搜索二叉树: {7,1,12,0,4,11,14,#,#,3,5},如下图:
示例1
输入:
{7,1,12,0,4,11,14,#,#,3,5},1,12
复制返回值:
7
复制说明:
节点1 和 节点12的最近公共祖先是7
示例2
输入:
{7,1,12,0,4,11,14,#,#,3,5},12,11
复制返回值:
12
复制说明:
因为一个节点也可以是它自己的祖先.所以输出12
题解
通过获取路径进行比较
思路:
- 1. 获取到达指定节点的路径
- 2. 比较路径上的节点,第一个不同的前一个节点就是他们的最近公共祖先,或者反向比较第一个相同的就是他们的最近公共祖先
这里使用反向比较,不用保存前一节点
// https://www.nowcoder.com/practice/d9820119321945f588ed6a26f0a6991f?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
struct TreeNode
{
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
std::vector<TreeNode *> find(TreeNode *root, int val)
{
std::vector<TreeNode *> v;
auto node = root;
while (node->val != val)
{
v.push_back(node);
if (node->val < val)
{
node = node->right;
}
else
{
node = node->left;
}
}
v.push_back(node);
return v;
}
int lowestCommonAncestor(TreeNode *root, int p, int q)
{
auto a = find(root, p);
auto b = find(root, q);
if (a.size() > b.size())
{
a.swap(b);
}
for (int i = a.size() - 1; i >= 0; --i)
{
for (int k = b.size() - 1; k >= 0; k--)
{
if (a[i] == b[k])
{
return a[i]->val;
}
}
}
return p;
}
通过一次遍历获取最近公共祖先
对于一颗搜索二叉树,给定2个值a和b,在我们遍历树的过程中,假设当前节点的值为x,有以下结论:
- 1. a 等于 x 或者 b 等于 x:那么当前节点一定是a和b最近的公共祖先
- 2. a > x 且 b < x或者a < x 且 b > x:说明在查找的过程中刚好在当前节点分道扬镳,因此当前节点就是他们最近的公共祖先
- 3. a和b都小于x:说明他们的最近公共祖先在x的左结点
- 4. a和b都大于x:说明他们的最近公共祖先在x的右结点
代码实现如下:
int lowestCommonAncestor_r(TreeNode *root, int p, int q)
{
if (root->val == p || root->val == q)
{
return root->val;
}
if (root->val > p && root->val > q)
{
return lowestCommonAncestor_r(root->left, p, q);
}
if (root->val < p && root->val < q)
{
return lowestCommonAncestor_r(root->right, p, q);
}
return root->val;
}