目录
1,题目描述
Sample Input:
7
1 2 3 4 5 6 7
2 3 1 5 4 7 6
Sample Output:
3
题目大意
利用二叉树的先序和中序遍历,输出后序遍历的第一个节点。
2,思路
先序遍历+中序遍历=》后序遍历。
构建过程可以参考@&再见萤火虫&【PAT_甲级_1020 Tree Traversals (25分) (C++)【树的遍历】】
这里只需要输出后序遍历的第一个数字,即整棵树的第一个叶节点。
用left和right限定中序遍历的左右界限,root指定先序遍历中的首节点(整棵树的根节点)
只要有左子树,就不断缩减右边界;无左子树(in[left]==pre[root])且left<right,说明仍未找到叶节点,便增加左边界,遍历右子树寻找第一个叶节点;
当左右边界重合时,便找到了第一个叶节点!
(注意,在寻找根节点pre[root]在中序遍历中的位置。以便分割子树时,可以用map记录值在中序遍历(in)中的位置,可以节省很多时间)
3,AC代码
#include<bits/stdc++.h>
using namespace std;
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
int N, pre[50005], in[50005];
cin>>N;
unordered_map<int, int> inMap;
for(int i = 0; i < N; i++)
scanf("%d", &pre[i]);
for(int i = 0; i < N; i++){
scanf("%d", &in[i]);
inMap[in[i]] = i;
}
int left = 0, right = N-1, root = 0;
while(left < right){ //left=right时 即为第一个叶节点
int i = inMap[pre[root]];
if(i > left){ //有左子树
right = i - 1;
root++;
}else{ //无左子树 且右子树不为空
root += (i - left + 1);
left = i + 1;
}
}
cout<<in[left]; //left=right 合并为一个节点
return 0;
}
4,解题过程
第一搏
???这不是简化版的先序加中序-》后序吗
#include<bits/stdc++.h>
using namespace std;
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
int N, pre[50005], in[50005];
cin>>N;
for(int i = 0; i < N; i++)
scanf("%d", &pre[i]);
for(int i = 0; i < N; i++)
scanf("%d", &in[i]);
bool flag = false;
int left = 0, right = N-1, root = 0;
while(left <= right && in[right] != pre[root]){
int i = left;
while(i <= right && in[i] != pre[root])
i++;
right = i - 1;
root++;
}
cout<<pre[root];
return 0;
}
第二搏
重新考虑了一下,发现这里的逻辑有问题:
只考虑了左子树的情况,没有想到左子树为空的情况,于是改进了一下:
第三搏
这复杂度要是超时,真的没有算法可以解决了。。。
所以我怀疑是边界没处理好,陷入了死循环。。。
最终锁定这里【语句顺序写反了!!!】
#include<bits/stdc++.h>
using namespace std;
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
int N, pre[50005], in[50005];
cin>>N;
for(int i = 0; i < N; i++)
scanf("%d", &pre[i]);
for(int i = 0; i < N; i++)
scanf("%d", &in[i]);
int left = 0, right = N-1, root = 0;
while(left < right){
int i = left;
while(i <= right && in[i] != pre[root])
i++;
if(i > left){//有左子树
right = i - 1;
root++;
}else{
root += (i - left + 1);
left = i + 1;
//root += (i - left + 1); !!!此时left已经改变
}
}
cout<<in[left];
return 0;
}
622ms。。。
擦枪走火的感觉可太刺激了。。。
第四搏
突然又注意到这里查找根节点是O(N)的复杂度。。。为什么不用map记录中序遍历中各节点的位置呢?
于是
高呼666!(o゜▽゜)o☆[BINGO!]