0
点赞
收藏
分享

微信扫一扫

PAT_甲级_1138 Postorder Traversal (25point(s)) (C++)【树的遍历/先序+中序->后序】


目录

​​1,题目描述​​

​​题目大意​​

​​2,思路​​

​​3,AC代码​​

​​4,解题过程​​

​​第一搏​​

​​第二搏​​

​​第三搏​​

​​第四搏​​

1,题目描述

PAT_甲级_1138 Postorder Traversal (25point(s)) (C++)【树的遍历/先序+中序->后序】_甲级

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;
}

PAT_甲级_1138 Postorder Traversal (25point(s)) (C++)【树的遍历/先序+中序->后序】_1138_02

第二搏

重新考虑了一下,发现这里的逻辑有问题:

PAT_甲级_1138 Postorder Traversal (25point(s)) (C++)【树的遍历/先序+中序->后序】_树的遍历_03

只考虑了左子树的情况,没有想到左子树为空的情况,于是改进了一下:

PAT_甲级_1138 Postorder Traversal (25point(s)) (C++)【树的遍历/先序+中序->后序】_树的遍历_04

PAT_甲级_1138 Postorder Traversal (25point(s)) (C++)【树的遍历/先序+中序->后序】_树的遍历_05

第三搏

这复杂度要是超时,真的没有算法可以解决了。。。

所以我怀疑是边界没处理好,陷入了死循环。。。

最终锁定这里【语句顺序写反了!!!】

PAT_甲级_1138 Postorder Traversal (25point(s)) (C++)【树的遍历/先序+中序->后序】_1138_06

#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;
}

PAT_甲级_1138 Postorder Traversal (25point(s)) (C++)【树的遍历/先序+中序->后序】_1138_07

622ms。。。

PAT_甲级_1138 Postorder Traversal (25point(s)) (C++)【树的遍历/先序+中序->后序】_C++_08

擦枪走火的感觉可太刺激了。。。

第四搏

突然又注意到这里查找根节点是O(N)的复杂度。。。为什么不用map记录中序遍历中各节点的位置呢?

PAT_甲级_1138 Postorder Traversal (25point(s)) (C++)【树的遍历/先序+中序->后序】_PAT_09

于是

PAT_甲级_1138 Postorder Traversal (25point(s)) (C++)【树的遍历/先序+中序->后序】_C++_10

PAT_甲级_1138 Postorder Traversal (25point(s)) (C++)【树的遍历/先序+中序->后序】_PAT_11

高呼666!(o゜▽゜)o☆[BINGO!]

 

 

举报

相关推荐

0 条评论