A1043
个人思路
个人认为这道题严谨性不够。原因见下文的本题思路
个人思路依据二叉查找树中序序列有序的性质求解
- 拿到pre[]后,从小到大排序为正常的二叉查找树的中序序列;从大到小排列为镜像二叉查找树的中序序列。
- 由pre[]和in[]可构建二叉查找树
- 在构建过程中,如果在in[]中找不到pre[]的根节点,说明无法建树,输出NO,否则输出yes和后序序列
但这样分析有一个问题,对于样例二(实际是镜像)
7
8 10 11 8 6 7 5 (pre[])
11 10 8 8 7 6 5 (in[])
注意:pre[0]的“8”并非in[2]的“8”,而是in[3]的“8”;这居然涉及到排序的稳定性问题了????一下子把我搞蒙了。硬着头皮写完提交一下发现只有一个用例没过。可能是用例设计的不够全面
值得借鉴的是:判断给出的pre[]是正常树还是镜像树的方法:比较pre[0]与pre[1]的大小,正常树应该试是pre[0]根节点大于pre[1]左子节点
个人思路的代码
有一条记录未通过
#include <bits/stdc++.h>
using namespace std;
int N, pos;
int pre[1005], in[1005];
bool flag = true;//标记是否可以构成树,默认为可以的
vector<int> post;
struct Node{
int data;
int lchild;
int rchild;
Node(){}
Node(int d, int l, int r)
{
data = d;
lchild = l;
rchild = r;
}
}nodes[1005];
int newNode(int v)
{
nodes[pos] = Node(v, -1, -1);
return pos++;
}
int recreate(int preL, int preR, int inL, int inR)
{
if(!flag)
return -1;//-1代表不能构成树
if(preL > preR)//边界
return -1;
int root = newNode(pre[preL]);
int k;
for(k = inL; k <= inR; ++k)
{
if(in[k] == pre[preL])
break;
}
if(k == inR + 1)//不能构成树
{
flag = false;
return -1;
}
int numLeft = k - inL;
nodes[root].lchild = recreate(preL + 1, preL + numLeft, inL, k - 1);
nodes[root].rchild = recreate(preL + numLeft + 1, preR, k + 1, inR);
return root;
}
void postOrder(int root)
{
if(root == -1)
return;
postOrder(nodes[root].lchild);
postOrder(nodes[root].rchild);
post.push_back(nodes[root].data);
}
bool cmp(int a, int b)
{
return a > b;
}
int main(int argc, char *argv[]) {
scanf("%d", &N);
for(int i = 0; i < N; ++i)
{
scanf("%d", &pre[i]);
in[i] = pre[i];
}
if(pre[0] > pre[1])
sort(in, in + N);//根据二查找叉树中序的性质
else
sort(in, in + N, cmp);
int root = recreate(0, N - 1, 0, N - 1);
if(flag == false)
printf("NO");
else
{
printf("YES\n");
postOrder(root);
for(int i = 0; i < post.size(); ++i)
{
if(i < post.size() - 1)
printf("%d ", post[i]);
else
printf("%d", post[i]);
}
}
return 0;
}
本题思路
- 根据题目给出的先序序列构建二叉查找树
- 再先序遍历二叉查找树(按正常和镜像方式逐一遍历)
镜像遍历,只不过是左右孩子遍历顺序先后发生变化 - 当遍历结果与给出结果一致时,输出yes,否则输出no
本题不合理之处:由先序推导二叉树原本就不可逆的操作,且先序也无法完全唯一确定二叉查找树,为什么要通过给出的先序构建树再反过来验证呢??可能本题的本意就是要验证的意思??个人感觉经不起推敲
AC代码
#include <bits/stdc++.h>
using namespace std;
int N, pos;
vector<int> origin, pre, post;
struct Node{
int data;
int lchild;
int rchild;
Node(){}
Node(int d, int l, int r)
{
data = d;
lchild = l;
rchild = r;
}
}nodes[1005];
int newNode(int v)
{
nodes[pos] = Node(v, -1, -1);
return pos++;
}
void insert(int &root, int v)//构建二叉查找树
{
if(root == -1)//说明查找v失败,即是插入位置
{
root = newNode(v);
return;
}
if(v >= nodes[root].data)//大于等于在右子树
insert(nodes[root].rchild, v);
else
insert(nodes[root].lchild, v);
}
void preOrder(int root)//正常前序
{
if(root == -1)
return;
pre.push_back(nodes[root].data);
preOrder(nodes[root].lchild);
preOrder(nodes[root].rchild);
}
void mirrorPre(int root)//镜像前序
{
if(root == -1)
return;
pre.push_back(nodes[root].data);
mirrorPre(nodes[root].rchild);
mirrorPre(nodes[root].lchild);
}
void postOrder(int root)//正常后序
{
if(root == -1)
return;
postOrder(nodes[root].lchild);
postOrder(nodes[root].rchild);
post.push_back(nodes[root].data);
}
void mirrorPost(int root)//镜像后序
{
if(root == -1)
return;
mirrorPost(nodes[root].rchild);
mirrorPost(nodes[root].lchild);
post.push_back(nodes[root].data);
}
int main(int argc, char *argv[]) {
scanf("%d", &N);
int root = -1;//存放根节点地址 ,注意先声明为-1
for(int i = 0; i < N; ++i)
{
int num;
scanf("%d", &num);
origin.push_back(num);
insert(root, num);
}
if(origin[0] > origin[1])//正常树
{
preOrder(root);
if(pre == origin)
{
printf("YES\n");
postOrder(root);
for(int i = 0; i < post.size(); ++i)
{
if(i < post.size() - 1)
printf("%d ", post[i]);
else
printf("%d", post[i]);
}
}
else
printf("NO");
}
else//镜像
{
mirrorPre(root);
if(pre == origin)
{
printf("YES\n");
mirrorPost(root);
for(int i = 0; i < post.size(); ++i)
{
if(i < post.size() - 1)
printf("%d ", post[i]);
else
printf("%d", post[i]);
}
}
else
printf("NO");
}
return 0;
}