关于二叉树的题目总结(PAT)

PAT比较喜欢考察二叉树,二叉树的题目难度不大但也并不容易,需要对二叉树的遍历、性质比较熟悉才能快速获得思路,完成解答。现在整理一些题目以供巩固和以后复习。
github地址

PAT 1020 Tree Traversals (25分)

思路

已知后序遍历和中序遍历求层序遍历。首先使用递归的方法重构二叉树,再使用bfs完成层序遍历即可。
PAT1020

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
using namespace std;
#define MAX 10010
int post[MAX];
int in[MAX];
int node[MAX];
void rebuild(int pL,int pR, int iL, int iR, int n)
{
    if(iL>iR)
    {
        node[n] = -1;
        return;
    }
    int root = post[pR];
    node[n] = root;
    int m = find(in,in+iR,root) - in;

    int cnt = m-iL;
    rebuild(pL,pL+cnt-1,iL,m-1,2*n);
    rebuild(pL+cnt,pR-1,m+1,iR,2*n+1);
}
void bfs()
{
    queue<int> q;
    q.push(1);
    bool space = false;
    while(q.size())
    {
        int n = q.front();
        int val = node[n];
        q.pop();
        if(val>0)
        {
            if(space)
                printf(" ");
            else space = true;
            printf("%d",val);
            q.push(2*n);
            q.push(2*n+1);
        }
    }
}
int main()
{
    int N;
    scanf("%d",&N);
    for(int i=0;i<N;i++)
        scanf("%d",&post[i]);
    for(int i=0;i<N;i++)
        scanf("%d",&in[i]);
    rebuild(0,N-1,0,N-1,1);

    bfs();
    return 0;
}

PAT 1064 Complete Binary Search Tree (30分)

PAT1064
嗯,终于来了个30分的。
给一个完全搜索二叉树前序遍历的求层序遍历。

思路

二叉搜索树树中序遍历是有小到大排序。
构建一个数组存储节点,下标为n的节点的子节点的下标分别是2 * n,2 * n + 1,因为是完全二叉树,所以二叉树的节点下标就是1~N。
而层序遍历就是这个节点数组。
利用这几个性质即可完成题目。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#define MAX 2010
using namespace std;
int N;
int pos=0;
int ar[MAX];
int node[MAX];
bool cmp(int a, int b)
{
    if(node[a]<node[b])
        return true;
    return false;
}
void build(int root)
{
    if(root>N)
        return;
    int lc = 2*root;
    int rc = 2*root+1;
    build(2*root);
    node[root]=ar[pos++];
    build(2*root+1);
}
int main()
{
    scanf("%d",&N);
    for(int i=0;i<N;i++)
        scanf("%d",&ar[i]);
    sort(ar,ar+N);
    build(1);
    for(int i=1;i<=N;i++)
    {
        if(i!=1)
            printf(" ");
        cout<<node[i];
    }

}

PAT 1086 Tree Traversals Again (25分)

PAT1086

思路

实际上就是已知中序前序求后序遍历。方法是递归重构二叉树。

#include <string>
#include <cstdio>
#include <iostream>
#include <stack>
#include <algorithm>
using namespace std;
#define MAX 800
int N;
int pre[MAX];
int in[MAX];
int post[MAX];
int node[MAX];
stack<int> s;
int pos = 0;
void rebuild(int L, int R, int n)
{
    if(L>=R)
    {
        node[n] = -1;
        return;
    }
    int root = pre[pos++];
    node[n] = root;
    int m = find(in, in+R,root) - in;
    rebuild(L,m,2*n);
    rebuild(m+1,R,2*n+1);
}
int k2 = 0;
void pushit(int n)
{
    if(node[n]<0)
        return;
    pushit(2*n);
    pushit(2*n+1);
    post[k2++] = node[n];
}
int main()
{
    scanf("%d",&N);
    int k0 = 0;
    int k1 = 0;
    for(int i=1;i<=2*N;i++)
    {
        string op;
        cin>>op;
        if(op=="Push\0"){
            int val;
            cin>>val;
            s.push(val);
            pre[k0++] = val;
        }
        else{
            in[k1++] = s.top();
            s.pop();
        }
    }
    rebuild(0,N,1);
    pushit(1);
    for(int i=0;i<N;i++)
    {
        if(i!=0)
            printf(" ");
        printf("%d",post[i]);
    }
    return 0;
}

PAT 1043 Is it a Binary Search Tree(25分)

PAT1043
题目描述就不贴了。

解法1

解法一是比较容易想到的方法,但是调通却花了我很长时间。原因无他,就是太菜,而且在家确实专注度不高。

思路:

二叉搜索树一个重要性质:中序遍历就是其由小到大排序。
而镜像二叉搜索树就是其又大到小排序。
然后就是已知前序和中序求后序遍历,可以参考PAT1086的解法。如果其前序和中序无法构建一个二叉树,则后序遍历数组是不会得到N个节点的值的,因此我们可以通过判断后序遍历数组来判定给定的前序遍历数组会不会是一个二叉搜索树的前序前序遍历结果。
同时还需要注意一个问题:二叉搜索树等于父节点的子节点只能在右子树,而镜像二叉搜索树等于父节点的子节点只能在左子树。

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;
int N;
vector<int> pre,in,post;
bool is_mirror = false;
void getPost(int root,int iL, int iR)
{
    if(iL>iR)
        return;
    int pos = iR+1;
    if(!is_mirror)
    {
        for(int i=iL;i<=iR;i++)
        {
            if(pre[root]==in[i])
            {
                pos = i;
                break;
            }
        }
    }
    else{
        for(int i=iL;i<=iR;i++)
        {
            if(pre[root]==in[i])
                pos = i;
        }
    }
    getPost(root+1,iL,pos-1);
    getPost(root+pos-iL+1,pos+1,iR);
    post.push_back(pre[root]);
}
int main()
{
    scanf("%d",&N);
    pre.resize(N);
    in.resize(N);
    for(int i=0;i<N;i++)
    {
        scanf("%d",&pre[i]);
        in[i] = pre[i];
    }
    sort(in.begin(),in.end());
    getPost(0,0,N-1);
    if(post.size()==N)
    {
        printf("YES\n");
    }
    else{
        is_mirror = true;
        post.clear();
        reverse(in.begin(),in.end());
        getPost(0,0,N-1);
        if(post.size()==N)
            printf("YES\n");
        else{
            printf("NO\n");
            return 0;
        }
    }
    for(int i=0;i<N;i++)
    {
        if(i!=0)
            printf(" ");
        printf("%d",post[i]);
    }
    return 0;
}

解法2

思路:

解法2更加巧妙。二叉树的右子树大于等于父节点,左子树小于父节点。在前序遍历数组中,第一个节点是根节点,然后是左子树的前序遍历数组,最后是右子树前序遍历数组。所以我们找到右子树第一个节点,左子树的最后一个节点,就可找到左子树数组,右子树数组。如果能够构建一个二叉树,那么右子树的第一个节点的索引一定等于左子树最后一个节点的索引+1。最后就可以通过递归来获取后序遍历数组了。

代码

#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#define MAX 1010
using namespace std;
int N;
int pre[MAX];
vector<int> post;
bool is_mirror = false;
void rebuild(int L, int R)
{
    if(L>R)
        return;
    int i = L+1;
    int j = R;
    if(!is_mirror)
    {
        while(i<=R&&pre[L]>pre[i]) i++;
        while(j>L&&pre[L]<=pre[j]) j--;
    }
    else{
        while(i<=R&&pre[L]<=pre[i]) i++;
        while(j>L&&pre[L]>pre[j]) j--;
    }
    if(i-j!=1)
        return;
    rebuild(L+1,j);
    rebuild(i,R);
    post.push_back(pre[L]);
}
int main()
{
    scanf("%d",&N);
    for(int i=0;i<N;i++)
        scanf("%d",&pre[i]);
    rebuild(0,N-1);
    if(post.size()==N)
        cout<<"YES"<<endl;
    else{
        post.clear();
        is_mirror = true;
        rebuild(0,N-1);
        if(post.size()==N)
            cout<<"YES"<<endl;
        else{
            cout<<"NO"<<endl;
            return 0;
        }
    }
    for(int i=0;i<N;i++)
    {
        if(i!=0)
            printf(" ");
        printf("%d",post[i]);
    }
    return 0;
}

PAT 1099 Build A Binary Search Tree(30分)

PAT1099
又是一个30分的。

思路

还是依然应用二叉搜索树的性质:中序遍历就是节点值由小到大排序。
声明一个结构体,存储节点的左子节点序号、右子节点序号、值。先求出中序遍历序号数组,然后与排序号的节点值对应起来。最后用bfs完成层序遍历。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#define MAX 110
using namespace std;
int N;
struct Node
{
    int lc;
    int rc;
    int val;
}node[MAX];
int ar[MAX];
int in[MAX];
int k=0;
void getIn(int ind)
{
    if(ind<0)
        return;
    getIn(node[ind].lc);
    in[k++] = ind;
    getIn(node[ind].rc);
}
void bfs()
{
    queue<Node> que;
    que.push(node[0]);
    bool space = false;
    while(que.size())
    {
        Node next = que.front();
        que.pop();
        if(next.lc>0)
            que.push(node[next.lc]);
        if(next.rc>0)
            que.push(node[next.rc]);
        if(space)
            printf(" ");
        else space = true;
        cout<<next.val;
    }
}
int main()
{
    scanf("%d",&N);
    for(int i=0;i<N;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        node[i].lc = a;
        node[i].rc = b;
    }
    for(int i=0;i<N;i++)
    {
        int x;
        scanf("%d",&x);
        ar[i] = x;
    }
    sort(ar,ar+N);
    getIn(0);
    for(int i=0;i<N;i++)
    {
        node[in[i]].val = ar[i];
    }
    bfs();
    printf("\n");
    return 0;
}

1066 Root of AVL Tree (25分)

题目链接
嗯 不会,有点麻烦,没有简便方法。只能建立一棵AVL树,需要注意的点很多。重点是LL旋、LR旋、RR旋、RL旋四种旋转方式。参考博客:https://blog.csdn.net/qq_35779286/article/details/88996548

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#define MAX
using namespace std;
int N;
typedef struct Node* tree;
struct Node
{
    int v;
    tree left;
    tree right;
};
tree build(int N);
tree newnode(int v);
tree insert(tree T, int v);
int height(tree T);
tree LLrotation(tree T);
tree LRrotation(tree T);
tree RRrotation(tree T);
tree RLrotation(tree T);
int main()
{
    scanf("%d",&N);
    tree T = build(N);
    printf("%d\n",T->v);
    return 0;
}
tree build(int n)
{
    int v;
    scanf("%d",&v);
    tree T = newnode(v);
    for(int i=1;i<n;i++)
    {
        scanf("%d",&v);
        T = insert(T,v);
    }
    return T;
}
tree newnode(int v)
{
    tree T = (tree)malloc(sizeof(struct Node));
    T->v = v;
    T->left = NULL;
    T->right = NULL;
    return T;
}
tree insert(tree T, int v)
{
    if(!T)
        T = newnode(v);
    else{
        if(v<T->v)
        {
            T->left = insert(T->left, v);
            if(height(T->left)-height(T->right)==2)
            {
                if(v < T->left->v)
                    T = LLrotation(T);
                else T = LRrotation(T);
            }
        }
        else{
            T->right = insert(T->right, v);
            if(height(T->right)-height(T->left)==2)
            {
                if(v<T->right->v)
                    T = RLrotation(T);
                else T = RRrotation(T);
            }
        }
    }
    return T;
}
int height(tree T)
{
    int hl,hr,maxi;
    if(T)
    {
        hl = height(T->left);
        hr = height(T->right);
        maxi = hl > hr ? hl : hr;
        return maxi+1;
    }
    else return 1;
}
tree LLrotation(tree T)
{
    tree a = T, b = T->left;
    tree bl = b->left, br = b->right, ar = a->right;
    a->left = br;
    a->right = ar;
    b->left = bl;
    b->right = a;
    return b;
}
tree LRrotation(tree T)
{
    tree a = T, b = T->left, c = b->right;
    tree bl = b->left, cl = c->left, cr = c->right, ar=a->right;
    b->left = bl;
    b->right = cl;
    a->left = cr;
    a->right = ar;
    c->left = b;
    c->right = a;
    return c;
}
tree RRrotation(tree T)
{
    tree a = T, b = T->right;
    tree al = a->left, bl = b->left, br = b->right;
    a->left = al;
    a->right = bl;
    b->left = a;
    b->right = br;
    return b;
}
tree RLrotation(tree T)
{
    tree a = T, b=T->right, c=b->left;
    tree al = a->left, br=b->right, cl=c->left,cr=c->right;
    a->left = al;
    a->right = cl;
    b->left = cr;
    b->right = br;
    c->left = a;
    c->right = b;
    return c;
}


PAT 1123 Is It a Complete AVL Tree (30分)

题目链接
前一题+bfs遍历就完事儿了。
不过我太粗心了,总有错误,找bug找很久。。。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <queue>
using namespace std;
int N;
typedef struct Node* tree;
struct Node
{
    int val;
    tree left;
    tree right;
};
int maxiindex = 0;
tree build(int N);
tree insert(tree T, int v);
tree newnode(int v);
int height(tree T);
tree LLrotation(tree T);
tree LRrotation(tree T);
tree RLrotation(tree T);
tree RRrotation(tree T);
void bfs(tree T);
int main()
{
    scanf("%d",&N);
    tree T = build(N);
    bfs(T);
    if(maxiindex==N)
        printf("YES\n");
    else printf("NO\n");
    return 0;
}
void bfs(tree T)
{
    if(!T)
        return;
    queue<pair<tree,int> > que;
    que.push(make_pair(T,1));
    bool space = false;
    while(que.size())
    {
        tree next = que.front().first;
        int faindex = que.front().second;
        maxiindex = max(faindex, maxiindex);
        que.pop();
        if(space)
            printf(" ");
        else space = true;
        printf("%d",next->val);
        if(next->left)
            que.push(make_pair(next->left,2*faindex));
        if(next->right)
            que.push(make_pair(next->right,2*faindex+1));
    }
    printf("\n");
}
tree build(int N)
{
    int v;
    scanf("%d",&v);
    tree T = newnode(v);
    for(int i=1;i<N;i++)
    {
        scanf("%d",&v);
        T = insert(T, v);
    }
    return T;
}
tree newnode(int v)
{
    tree T = (tree)malloc(sizeof(struct Node));
    T->val = v;
    T->left = NULL;
    T->right = NULL;
    return T;
}
tree insert(tree T, int v)
{
    if(!T)
        T = newnode(v);
    else{
        if(v<T->val)
        {
            T->left = insert(T->left, v);
            if(height(T->left)==height(T->right)+2)
            {
                if(v<T->left->val)
                    T = LLrotation(T);
                else T = LRrotation(T);
            }
        }
        else{
            T->right = insert(T->right, v);
            if(height(T->right)==height(T->left)+2)
            {
                if(v<T->right->val)
                    T = RLrotation(T);
                else T = RRrotation(T);
            }
        }
    }
    return T;
}
int height(tree T)
{
    int hl, hr, maxi;
    if(T)
    {
        hl = height(T->left);
        hr = height(T->right);
        maxi = max(hl,hr);
        return maxi+1;
    }
    else return 1;
}
tree LLrotation(tree T)
{
    tree A = T, B = T->left;
    tree AR = A->right, BL = B->left, BR = B->right;
    A->left = BR;
    B->right = A;
    return B;
}
tree LRrotation(tree T)
{
    tree A = T, B = T->left;
    tree AR = A->right;
    tree C = B->right;
    tree BL = B->left;
    tree CL = C->left;
    tree CR = C->right;
    C->left = B;
    C->right = A;
    B->right = CL;
    A->left = CR;
    return C;
}
tree RRrotation(tree T)
{
    tree A = T, B = T->right;
    tree AL = A->left, BL = B->left, BR = B->right;
    A->right = BL;
    B->left = A;
    return B;
}
tree RLrotation(tree T)
{
    tree A = T, B = T->right;
    tree C = B->left, AL = A->left, CL = C->left, CR = C->right, BR = B->right;
    C->left = A;
    C->right = B;
    A->right = CL;
    B->left = CR;
    return C;
}

1102 Invert a Binary Tree (25分)

题目链接
相当基础的一道题了。

代码

#include <iostream>
#include <cstring>
#include <queue>
#include <cstdio>
#define MAX 12
using namespace std;

int N;
struct Node
{
    int lc;
    int rc;
}node[MAX];
bool isroot[MAX];
void bfs(int r)
{
    queue<int> que;
    que.push(r);
    bool space = false;
    while(!que.empty())
    {
         int next = que.front();
         que.pop();
         int lc = node[next].lc;
         int rc = node[next].rc;
         if(space)
             printf(" ");
         else space = true;
         printf("%d",next);
         if(rc>=0)
            que.push(rc);
         if(lc>=0)
            que.push(lc);
    }
    printf("\n");
}
bool inspace = false;
void inorder(int r)
{
    if(r<0)
       return;
    inorder(node[r].rc);
    if(inspace)
       printf(" ");
    else inspace = true;
    printf("%d",r);
    inorder(node[r].lc);
}
int main()
{
    scanf("%d",&N);
    fill(isroot,isroot+N,true);
    getchar();
    for(int i=0;i<N;i++)
    {
        char a,b;
        scanf("%c %c",&a,&b);
        if(a=='-') node[i].lc = -1;
        else{
            node[i].lc = int(a-48);
            isroot[node[i].lc] = false;
        }
        if(b=='-') node[i].rc = -1;
        else{
            node[i].rc = int(b-48);
            isroot[node[i].rc] = false;
        }
        getchar();
    }
    int root = 0;
    for(int i=0;i<N;i++)
    {
        if(isroot[i])
        {
             root = i;
             break;
        }
    }
    bfs(root);
    inorder(root);
    printf("\n");

    return 0;
}

PAT 1110 Complete Binary Tree (25分)

题目链接
又是一个比较简单的题目吧。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#define MAX 25

using namespace std;
 struct Node
 {
     int lc;
     int rc;
 }node[MAX];
int N;
bool is_root[MAX];
int maxi = -1;
int ans = 0;
void dfs(int r, int index)
{
    if(index>maxi)
    {
        ans = r;
        maxi = index;
    }
    if(node[r].lc>=0)
        dfs(node[r].lc, 2*index+1);
    if(node[r].rc>=0)
        dfs(node[r].rc, 2*index+2);
}
int main()
{
    scanf("%d",&N);
    fill(is_root,is_root+N,true);
    for(int i=0;i<N;i++)
    {
        string a,b;
        cin>>a>>b;
        if(a=="-")
        {
            node[i].lc = -1;

        }
        else{
            node[i].lc = stoi(a);
            is_root[node[i].lc] = false;
        }
        if(b=="-")
        {
            node[i].rc = -1;

        }
        else{
            node[i].rc = stoi(b);
            is_root[node[i].rc] = false;

        }
    }
    int root = 0;
    for(int i=0;i<N;i++)
    {
        if(is_root[i])
        {
            root = i;
            break;
        }
    }
    dfs(root,0);
    //cout<<maxi<<endl;
    if(maxi==N-1)
    {
        printf("YES %d\n",ans);
    }
    else{
        printf("NO %d\n",root);
    }
    return 0;
}

PAT 1127 ZigZagging on a Tree (30分)

题目链接
这题其实也不难。就是个递归重建二叉树,用bfs求每层的节点,最后根据节点的层树正序\反序输出即可。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
#define MAX 32
using namespace std;
int N;
int in[MAX];
int post[MAX];
vector<int> ans[MAX];
struct Node
{
    int val;
    int lc=-1;
    int rc=-1;
}node[MAX];
void rebuild(int iL,int iR,int pL,int pR,int rindex,bool flag)
{
    if(iL>iR||pL>pR)
        return;
    int rootval = post[pR];
    int m = find(in,in+N,rootval)-in;
    if(flag)
        node[rindex].lc = m;
    else node[rindex].rc = m;
    rebuild(iL,m-1,pL,pL+m-iL-1,m,true);
    rebuild(m+1,iR,pL+m-iL,pR-1,m,false);
}
int deep = 0;
void bfs()
{
    int root = find(in,in+N,post[N-1])-in;
    queue<pair<int,int> > que;
    que.push(make_pair(root,0));
    bool space = false;
    while(que.size())
    {
        int next = que.front().first;
        int step = que.front().second;
        que.pop();
        if(next<0)
            continue;
        int val = node[next].val;
        ans[step].push_back(val);
        deep = max(deep,step);
        int lc = node[next].lc;
        int rc = node[next].rc;
        int newstep = (step+1);
        que.push(make_pair(lc,newstep));
        que.push(make_pair(rc,newstep));
    }
}
int main()
{
    scanf("%d",&N);
    for(int i=0;i<N;i++)
    {
        scanf("%d",&in[i]);
        node[i].val = in[i];
    }
    for(int i=0;i<N;i++)
        scanf("%d",&post[i]);
    rebuild(0,N-1,0,N-1,N,true);
    bfs();
    bool space = false;
    for(int i=0;i<=deep;i++)
    {
        if(i%2==0)
        {
            for(int j=ans[i].size()-1;j>=0;j--)
            {
                if(space)
                    printf(" ");
                else space = true;
                printf("%d",ans[i][j]);
            }
        }
        else{
            for(int j=0;j<ans[i].size();j++)
            {
                printf(" ");
                printf("%d",ans[i][j]);
            }
        }
    }
    printf("\n");

    return 0;
}

PAT 1143 Lowest Common Ancestor (30分)

题目链接

思路1

这个题和后面的PAT1151是类似的。用的是比较容易想到的方法,二话不说递归重建二叉树(我先写的1151,然后看到1143,于是将1151的代码稍微改一下就可以过1143了。)

代码1

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <map>
#define MAX 10100
using namespace std;

int N,M;
int pre[MAX];
int in[MAX];
map<int,int> pos;
vector<int> ancestor[MAX];
//int father[MAX];
struct Node
{
    int val;
    int father=-1;
}node[MAX];
void rebuild(int iL,int iR,int pL,int pR,int rindex)
{
    if(iL>iR||pL>pR)
        return;
    int root = pre[pL];
    int m = pos[root];
    node[m].father = rindex;
    rebuild(iL,m-1,pL+1,pL+m-iL,m);
    rebuild(m+1,iR,pL+m-iL+1,pR,m);
}
int main()
{
    scanf("%d%d",&M,&N);
    for(int i=0;i<N;i++)
    {
        scanf("%d",&pre[i]);
        in[i] = pre[i];
    }
    sort(in,in+N);
    for(int i=0;i<N;i++)
    {
        node[i].val = in[i];
        pos[node[i].val] = i;
    }
    rebuild(0,N-1,0,N-1,-1);
    for(int i=0;i<M;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        if(pos.find(a)==pos.end())
        {
            if(pos.find(b)==pos.end())
            {
                printf("ERROR: %d and %d are not found.\n",a,b);
            }
            else{
                printf("ERROR: %d is not found.\n",a);
            }
        }
        else if(pos.find(b)==pos.end())
        {
            printf("ERROR: %d is not found.\n",b);
        }
        else{
            if(a==b)
            {
                printf("%d is an ancestor of %d.\n",a,b);
                continue;
            }
            int aindex = pos[a];
            int bindex = pos[b];
            int ra = aindex;
            int rb = bindex;
            vector<int> afa, bfa;
            bool flag = true;
            while(ra!=-1)
            {
                afa.push_back(ra);
                if(node[ra].father == bindex)
                {
                    flag = false;
                    printf("%d is an ancestor of %d.\n",b, a);
                    break;
                }
                ra = node[ra].father;
            }
            while(flag&&rb!=-1)
            {
                bfa.push_back(rb);
                if(node[rb].father == aindex)
                {
                    printf("%d is an ancestor of %d.\n",a, b);
                    flag = false;
                    break;
                }
                rb = node[rb].father;
            }
            if(flag)
            {
                int ai = afa.size()-1;
                int bj = bfa.size()-1;
                while(ai>=0&&bj>=0&&afa[ai]==bfa[bj])
                {
                    ai--;
                    bj--;
                }
                printf("LCA of %d and %d is %d.\n",a, b, in[afa[ai+1]]);
            }
        }
    }
    return 0;
}

思路2

非常巧妙,充分利用二叉搜索树的性质。
设U,V的LCA为ans:
1、中序遍历是左子树、该节点、右子树的顺序遍历,所以ans一定在U和V之间。
2、前序遍历是该节点、左子树、右子树的顺序遍历,所以ans一定在U和V之前。
所以在pre数组从0开始遍历找到的第一个满足条件(ans>=U&&ans<=V)||(ans>=V&&ans<=U)就是U和V的最低共同祖先。
参考链接

代码2

#include <iostream>
#include <vector>
#include <cstdio>
#include <map>
#define MAX 10100
using namespace std;
map<int, bool> mp;
int M,N;
int pre[MAX];
int main()
{

    scanf("%d%d",&M,&N);
    for(int i=0;i<N;i++)
    {
        scanf("%d",&pre[i]);
        mp[pre[i]] = true;
    }
    for(int i=0;i<M;i++)
    {
        int U,V,ans;
        scanf("%d%d",&U,&V);
        for(int j=0;j<N;j++)
        {
            ans = pre[j];
            if((ans>=U&&ans<=V)||(ans>=V&&ans<=U))
                break;
        }
        if(!mp[U])
        {
            if(!mp[V])
                printf("ERROR: %d and %d are not found.\n",U,V);
            else printf("ERROR: %d is not found.\n",U);
        }
        else if(!mp[V])
            printf("ERROR: %d is not found.\n",V);
        else if(ans==U)
            printf("%d is an ancestor of %d.\n", ans, V);
        else if(ans==V)
            printf("%d is an ancestor of %d.\n",ans,U);
        else
            printf("LCA of %d and %d is %d.\n",U,V,ans);
    }
}

PAT 1151 LCA in a Binary Tree (30分)

题目链接

思路1

用的是比较容易想到的方法,递归重建二叉树。(但是比较麻烦,并且容易写错,花的时间也比较长。)

代码1

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <map>
#define MAX 10100
using namespace std;

int N,M;
int pre[MAX];
int in[MAX];
map<int,int> pos;
vector<int> ancestor[MAX];
int father[MAX];
struct Node
{
    int val;
    int father = -1;
}node[MAX];
void rebuild(int iL,int iR,int pL,int pR,int rindex)
{
    if(iL>iR||pL>pR)
        return;
    int root = pre[pL];
    int m = pos[root];
    node[m].father = rindex;
    rebuild(iL,m-1,pL+1,pL+m-iL,m);
    rebuild(m+1,iR,pL+m-iL+1,pR,m);
}
int main()
{
    scanf("%d%d",&M,&N);
    for(int i=0;i<N;i++)
    {
        scanf("%d",&in[i]);
        node[i].val = in[i];
        pos[node[i].val] = i;
    }
    for(int i=0;i<N;i++)
        scanf("%d",&pre[i]);
    rebuild(0,N-1,0,N-1,N);
    for(int i=0;i<M;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        if(pos.find(a)==pos.end())
        {
            if(pos.find(b)==pos.end())
            {
                printf("ERROR: %d and %d are not found.\n",a,b);
            }
            else{
                printf("ERROR: %d is not found.\n",a);
            }
        }
        else if(pos.find(b)==pos.end())
        {
            printf("ERROR: %d is not found.\n",b);
        }
        else{
            if(a==b)
            {
                printf("%d is an ancestor of %d.\n",a,b);
                continue;
            }
            int aindex = pos[a];
            int bindex = pos[b];
            int ra = aindex;
            int rb = bindex;
            vector<int> afa, bfa;
            bool flag = true;
            while(ra!=-1)
            {
                afa.push_back(ra);
                if(node[ra].father == bindex)
                {
                    flag = false;
                    printf("%d is an ancestor of %d.\n",b, a);
                    break;
                }
                ra = node[ra].father;

            }
            while(flag&&rb!=-1)
            {
                bfa.push_back(rb);
                if(node[rb].father == aindex)
                {
                    printf("%d is an ancestor of %d.\n",a, b);
                    flag = false;
                    break;
                }
                rb = node[rb].father;
            }
            if(flag)
            {
                int ai = afa.size()-1;
                int bj = bfa.size()-1;
                while(ai>=0&&bj>=0&&afa[ai]==bfa[bj])
                {
                    ai--;
                    bj--;
                }
                printf("LCA of %d and %d is %d.\n",a, b, in[afa[ai+1]]);
            }
        }
    }
    return 0;
}

思路2

与前一题思路2相同,这里只需用pos字典映射一下就可以转换成前一个问题。

代码2

#include <iostream>
#include <cstring>
#include <cstdio>
#include <map>
#define MAX 10100
using namespace std;

int M,N;
int pre[MAX];
int in[MAX];
map<int,int> pos;
int main()
{
    scanf("%d%d",&M,&N);
    for(int i=0;i<N;i++)
    {
        scanf("%d",&in[i]);
        pos[in[i]] = i;
    }
    for(int i=0;i<N;i++)
        scanf("%d",&pre[i]);
    for(int i=0;i<M;i++)
    {
        int U,V;
        scanf("%d%d",&U,&V);
        if(pos.find(U)==pos.end())
        {
            if(pos.find(V)==pos.end())
            {
                printf("ERROR: %d and %d are not found.\n",U,V);
            }
            else printf("ERROR: %d is not found.\n",U);
        }
        else if(pos.find(V)==pos.end())
            printf("ERROR: %d is not found.\n",V);
        else{
            int ans = 0;
            int posU = pos[U];
            int posV = pos[V];
            for(int i=0;i<N;i++)
            {
                int p = pos[pre[i]];
                if((p>=posU&&p<=posV)||(p>=posV&&p<=posU))
                {
                    ans = p;
                    break;
                }
            }
            ans = in[ans];
            if(ans==U)
                printf("%d is an ancestor of %d.\n",U,V);
            else if(ans==V)
                printf("%d is an ancestor of %d.\n",V,U);
            else printf("LCA of %d and %d is %d.\n",U,V,ans);
        }
    }
    return 0;
}

PAT 1147 Heaps(30分)

思路

就遍历判断一下就可。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int M,N;
bool space = false;
void postTraversal(int ar[1010], int r,int n)
{
    if(r>n)
        return;
    postTraversal(ar,2*r,n);
    postTraversal(ar,2*r+1,n);
    if(space)
        printf(" ");
    else space = true;
    printf("%d",ar[r]);
}
int main()
{
    scanf("%d%d",&M,&N);
    int ar[1010];
    for(int i=0;i<M;i++)
    {
        int flag;
        for(int j=1;j<=N;j++)
        {
            int x;
            scanf("%d",&x);
            ar[j] = x;
        }
        flag = ar[1] > ar[2] ? 1 : -1;
        for(int j=1;j<=N/2;j++)
        {
            int lc = 2*j;
            int rc = 2*j+1;
            if(flag==1&&(ar[j]<ar[lc]||(rc<=N&&ar[j]<ar[rc])))
                flag = 0;
            if(flag==-1&&(ar[j]>ar[lc]||(rc<=N&&ar[j]>ar[rc])))
                flag = 0;
        }
        if(flag==1)
            printf("Max Heap\n");
        else if(flag==-1)
            printf("Min Heap\n");
        else printf("Not Heap\n");
        space = false;
        postTraversal(ar,1,N);
        printf("\n");
    }

    return 0;
}

PAT 1119 Pre- and Post-order Traversals (30分)

题目链接

思路

已知前序后序求中序。

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#define MAX
using namespace std;

int N;
int pre[35];
int post[35];
int in[35];
int k=0;
bool flag = true;
void Inorder(int preL, int preR, int postL, int postR)
{
    if(preL>preR||postL>postR)
        return;
    if(preL==preR)
    {
        in[k++] = pre[preL];
        return;
    }
    int cnt = 0;
    while(post[postL+cnt]!=pre[preL+1])
        cnt++;
    cnt+=1;
    if(cnt==1&&preL+cnt==preR)
        flag = false;
    Inorder(preL+1,preL+cnt,postL,postL+cnt-1);
    in[k++] = pre[preL];
    Inorder(preL+cnt+1,preR,postL+cnt,postR-1);
}
int main()
{
    scanf("%d",&N);
    for(int i=0;i<N;i++)
        scanf("%d",&pre[i]);
    for(int i=0;i<N;i++)
        scanf("%d",&post[i]);
    Inorder(0,N-1,0,N-1);
    if(flag)
        printf("Yes\n");
    else
        printf("No\n");
    for(int i=0;i<N;i++)
    {
        if(i!=0)
            printf(" ");
        printf("%d",in[i]);
    }
    printf("\n");
    return 0;
}

PAT 1130 Infix Expression (25分)

题目链接

思路

这题还挺有意思的。题目也很清晰,就是个二叉树的中序遍历。然后需要主要括号的输出,遇到根节点和叶子节点不输出括号。

代码

#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
int N;
struct Node
{
    string val;
    int lc;
    int rc;
}node[22];
int father[22];
int root;
void inorder(int r)
{
    bool flag = node[r].lc>0||node[r].rc>0;
    if(flag&&r!=root)
        printf("(");
    if(node[r].lc>0)
        inorder(node[r].lc);
    cout<<node[r].val;
    if(node[r].rc>0)
        inorder(node[r].rc);
    if(flag&&r!=root)
        printf(")");
}
int main()
{
    scanf("%d",&N);
    for(int i=1;i<=N;i++)
        father[i] = i;
    for(int i=1;i<=N;i++)
    {
        cin>>node[i].val>>node[i].lc>>node[i].rc;
        father[node[i].lc] = i;
        father[node[i].rc] = i;
    }
    root = 1;
    while(father[root]!=root)
    {
        root = father[root];
    }
    inorder(root);
    printf("\n");
    return 0;
}

PAT 1135 Is It A Red-Black Tree (30分)

题目链接

思路

该题博客链接

代码

#include <iostream>
#include <vector>
#include <cstdio>
#include <cmath>
using namespace std;
int K;
struct Node
{
    int val;
    Node* lc,*rc;
};
Node* build(Node* root,int val)
{
    if(root==NULL)
    {
        root = new Node();
        root->val = val;
        root->lc = NULL;
        root->rc = NULL;
        return root;
    }
    else if(abs(val)<=abs(root->val))
        root->lc = build(root->lc,val);
    else root->rc = build(root->rc,val);
    return root;
}
bool judgeblk(Node* root)
{
    if(root==NULL)
        return true;
    if(root->val<0)
    {
        if(root->lc&&root->lc->val<0)
            return false;
        if(root->rc&&root->rc->val<0)
            return false;
    }
    return judgeblk(root->lc)&&judgeblk(root->rc);
}
int getblkNum(Node* root)
{
    if(root==NULL)
        return 0;
    int lc = getblkNum(root->lc);
    int rc = getblkNum(root->rc);
    return root->val > 0 ? max(lc,rc)+1:max(lc,rc); 
}
bool judgeblkNum(Node* root)
{
    if(root==NULL)
        return true;
    int lnum = getblkNum(root->lc);
    int rnum = getblkNum(root->rc);
    if(lnum!=rnum)
        return false;
    return judgeblkNum(root->lc) && judgeblkNum(root->rc);
}
int main()
{
    scanf("%d",&K);
    while(K--)
    {
        int N;
        scanf("%d",&N);
        vector<int> pre;
        pre.resize(N);
        Node* root = NULL;
        for(int i=0;i<N;i++)
        {
            scanf("%d",&pre[i]);
            root = build(root,pre[i]);
        }
        if(pre[0]<0||!judgeblk(root)||!judgeblkNum(root))
            printf("No\n");
        else printf("Yes\n");
    }
    return 0;
}

未完待续…

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值