最低公共祖先——二分+二叉树性质

最低公共祖先——二分+二叉树性质

树中两个结点 UV 的最低公共祖先(LCA)是指同时具有 UV 作为后代的最深结点。

二叉搜索树 (BST) 递归定义为具有以下属性的二叉树:

  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值
  • 若它的右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值
  • 它的左、右子树也分别为二叉搜索树

现在给定 BST 中的任意两个结点,请你找出它们的最低公共祖先。

输入格式

第一行包含两个整数 MN,分别表示询问结点对数以及二叉搜索树中的结点数量。

第二行包含 N 个不同整数,表示该二叉搜索树的前序遍历序列。

接下来 M 行,每行包含两个整数 UV,表示一组询问。

所有结点权值均在 int 范围内。

输出格式

对于每对给定的 UV,输出一行结果。

如果 UV 的 LCA 是 A,且 A 不是 UV,则输出 LCA of U and V is A.

如果 UV 的 LCA 是 A,且 AUV 中的一个,则输出 X is an ancestor of Y.,其中 X 表示 AY 表示另一个结点。

如果 UV 没有在 BST 中找到,则输出 ERROR: U is not found.ERROR: V is not found.ERROR: U and V are not found.

数据范围

1 ≤ M ≤ 1000 , 1≤M≤1000, 1M1000,

1 ≤ N ≤ 10000 1≤N≤10000 1N10000

输入样例:
6 8
6 3 1 2 5 4 8 7
2 5
8 7
1 9
12 -3
0 8
99 99
输出样例:
LCA of 2 and 5 is 3.
8 is an ancestor of 7.
ERROR: 9 is not found.
ERROR: 12 and -3 are not found.
ERROR: 0 is not found.
ERROR: 99 and 99 are not found.

 

题解:
  1. 考虑二叉树性质:

    • 若它的左子树不为空,则左子树上所有结点的值均小于等于它的根结点的值;
    • 若它的右子树不为空,则右子树上所有结点的值均大于等于它的根结点的值;
    • 它的左、右子树也分别为二叉查找树。

    因此我们可以得到,对于每对输入的节点a和b,我们从题目给点的所有节点的先序遍历顺序开始依次i遍历,只要遇到一个结点 V V V ,( a ≤ V a \leq V aV && b ≥ V b \geq V bV) || ( a ≥ V a \geq V aV && b ≤ V b \leq V bV) , 该结点就为节点a和b的结点。

  2. 考虑如何快速判断输入的结点是否存在树中

    只需要开一个新的数组,存储树的所有结点,按从小到大排序,进行二分查找即可。

 

代码:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 1e4+10;
        
int pre[N], n, m;
vector<int> sor;
int find(int x)
{
    int l = 0, r = n-1;
    while(l < r)
    {
        int mid = l + r >> 1;
        if(sor[mid] >= x) r = mid;
        else l = mid + 1;
    }
    if(sor[l] == x) return l;
    else return -1;
}
int main()
{

    scanf("%d%d", &m, &n);
    for(int i = 0; i < n; i++)
    {
        scanf("%d", &pre[i]);
        sor.push_back(pre[i]);
    }
    sort(sor.begin(),sor.end());
    while(m--)
    {
        int a,b;
        scanf("%d%d", &a, &b);
        int f_a = find(a), f_b = find(b);
        if(f_a != -1 && f_b != -1)
        {
            int father;
            for(int i = 0; i < n; i++)
            {
                if((a >= pre[i] && b <= pre[i]) || (a <= pre[i] && b >= pre[i]))
                {
                    father = pre[i];
                    break;
                }
            }
            if(a != father && b != father) printf("LCA of %d and %d is %d.\n", a,b,father);
            else if(a == father && b != father) printf("%d is an ancestor of %d.\n", a, b);
            else printf("%d is an ancestor of %d.\n", b, a);
        }
        else if(f_a == -1 && f_b == -1) printf("ERROR: %d and %d are not found.\n", a,b);
        else if(f_a == -1) printf("ERROR: %d is not found.\n", a);
        else if(f_b == -1) printf("ERROR: %d is not found.\n", b);
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值