PAT 甲级 1043 Is It a Binary Search Tree (25 分) 递归建树+子树类型

题意:

给定一棵树的先序遍历,问是不是BST 或者 MirrorImage; 是的话输出后序遍历

思路:

BST 和 Mirror Image 都有一个性质,就是可以通过先序遍历把树建出来,

因为对于一个先序遍历,第一个点是当前树的根结点,①如果有两颗子树的话,那后面必然分成两段,一段值全部小于根结点的值,另一段全部大于根结点的值;②如果只有一颗子树的话,要么全大于根结点的值要么全小于根结点的值。③其余情况不满足BST 或者 Mirror Image,在本题来说就是“NO”

BST 和 Mirror Image 也有区别,在于左子树大还是右子树大,确定以后后面的子树必须按照同样的规则;规则不符也是“NO”

现在我们用type表示BST 和 Mirror Image ,分别用1,0表示;如果当前类型还不确定,那type的值为-1;

类似于先序遍历+中序遍历的递归过程,直接对整个序列递归,每次确定当前树的根结点,然后找子树的类型以及左右子树的分割点,如果中间出现不合法的情况,ok设为false;

最后遍历后序输出

 

更简单的一种方法:https://blog.csdn.net/xiang_6/article/details/100535762

#include<bits/stdc++.h>

using namespace std;
const int maxn = 1e4 + 7;

int n, t, id = 1, tp = -1, type = -1, cnt = 0;
int a[maxn];
bool ok = true;
struct node {
    int v;
    int l, r;
}tr[maxn];

int getpos(int l, int r) {
    int t1, t2;
    for(t1 = l+1; t1 <= r; ++t1) if(a[t1] < a[l]) break;
    for(t2 = l+1; t2 <= r; ++t2) if(a[t2] > a[l]) break;
    if(t1 > r) {
        type = -1;
        return -1;
    }
    else if(t2 > r) {
        type = -1;
        return -1;
    }
    else if(t1 > t2) { // Mirror Image
        type = 0;
        for(int i = t1; i <= r; ++i) {
            if(a[i] > a[l]) { ok = false; break; }
        }
        for(int i = t2; i < t1; ++i) {
            if(a[i] < a[l]) { ok = false; break; }
        }
        return t1;
    }
    else if(t2 > t1) { // BST
        type = 1;
        for(int i = t2; i <= r; ++i) {
            if(a[i] < a[l]) { ok = false; break; }
        }
        for(int i = t1; i < t2; ++i) {
            if(a[i] > a[l]) { ok = false; break; }
        }
        return t2;
    }
}
void solve(int l, int r, int &root) {
    //cout << l << " +++++++ " << r << endl;
    if(l > r) return;
    root = id++;
    tr[root].v = a[l];
    int x = getpos(l, r);
    if(x == -1) {
        solve(l+1, r, tr[root].l);
    }
    else if(type == 0){
        if(!ok) return;
        if(tp == 1) {
            ok = false;
            return;
        }
        else {
            tp = 0;
            solve(l+1, x-1, tr[root].l);
            solve(x, r, tr[root].r);
        }
    }
    else if(type == 1) {
        if(!ok) return;
        if(tp == 0) {
            ok = false;
            return;
        }
        else {
            tp = 1;
            solve(l+1, x-1, tr[root].l);
            solve(x, r, tr[root].r);
        }
    }
}
void print(int id) {
    if(!id) return;
    print(tr[id].l);
    print(tr[id].r);
    if(cnt) {
        printf(" %d", tr[id].v);
    }
    else {
        cnt = 1;
        printf("%d", tr[id].v);
    }
}
int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
    }
    solve(1, n, t);
    if(!ok) {
        return 0*puts("NO");
    }
    puts("YES");
    print(1);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值