[算法笔记] PAT-ADV-1020
题目要求:给出二叉树的后序遍历序列和中序遍历序列,输出二叉树的层次遍历序列。
(传送门)
Sample Input
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
Sample Output
4 1 6 3 5 7 2
解题思路
首先,我们在数据结构课程中学过下面的结论:
- 后序遍历: 左 右 根
- 中序遍历: 左 根 右
显然,后序序列中的最后一个元素总是某个子树的根,叶子节点也算是一个子树 (可能你觉得这是一句废话)。
此外, 只要确定根,那么可以在中序的某一片段序列中 “分离” 出左右子树。
下面我们来分析一下 Sample ,解析如何从如上2个结论唯一确定一颗二叉树。
在后序序列中:
2 3 1 5 7 6 4
4 毫无疑问是整个二叉树的根。现在在中序序列中找出 4 的位置。
1 2 3
45 6 7
也就是说可以得到二叉树的基本结构如下:
图1
4
/ \
1,2,3 5,6,7
再看后序序列剩下的元素:
2 3 1 5 7
6
最后一个元素是 6, 说明在 6 是根。
在中序序列中:
1 2 3 | 4 | 5
67
说明在 图1 中, 6 是右子树的根。
图2
4
/ \
1,2,3 6
/ \
5 7
继续遍历后序序列:
2 3 1 5 7
5 和 7 既是叶子节点也是一个特殊的根。
此时,后序序列剩下:
2 3
1
中序序列为:
12 3
显然, 1 是根, 2 和 3 是 1 的右子树。以此类推, 2 是 3 的左子树。那么中序序列和后序序列唯一确定的二叉树如下:
4
/ \
1 6
\ / \
3 5 7
/
2
概括一下算法要点:
- 从右往左遍历后序序列,得到根
- 在中序序列中找到根,分离出左右子树
- 对左右子树进行同样的操作
不难看出,是一个递归。
数据结构课程上,在纸上这类题目大家都会画出来,但是一到 Code 层面,完整实现还是有点难度的。
最后解析一下代码实现。
- 参数
l和r: 中序序列inorder[l...r], 代表当前所处理的子树 rootIdxPost: 后序序列中根的位置。(实际上取值变化就是: (N-1), ..., 0 )
Tree createTree(int l, int r, int &rootIdxPost)
{
if (l > r)
return NULL;
if (l == r)
{
Tree t = new TreeNode(inorder[l]);
rootIdxPost--;
return t;
}
int rootVal = postorder[rootIdxPost--];
int rootIdxIn = findRoot(inorder, rootVal);
Tree root = new TreeNode(rootVal);
root->right = createTree(rootIdxIn + 1, r, rootIdxPost);
root->left = createTree(l, rootIdxIn - 1, rootIdxPost);
return root;
}
完整代码:
#include <cstdio>
#include <vector>
#include <assert.h>
#include <queue>
#define NMAX 35
using namespace std;
struct TreeNode
{
int val;
TreeNode *left, *right;
TreeNode(int v = -1, TreeNode *l = NULL, TreeNode *r = NULL) : val(v), left(l), right(r) {}
};
typedef TreeNode *Tree;
vector<int> postorder(NMAX), inorder(NMAX);
int N = 0;
int findRoot(vector<int> &inorder, int rootVal)
{
size_t len = inorder.size();
for (size_t i = 0; i < len; i++)
{
if (inorder[i] == rootVal)
return i;
}
assert(0);
return -1;
}
Tree createTree(int l, int r, int &rootIdxPost)
{
if (l > r)
return NULL;
if (l == r)
{
Tree t = new TreeNode(inorder[l]);
rootIdxPost--;
return t;
}
int rootVal = postorder[rootIdxPost--];
int rootIdxIn = findRoot(inorder, rootVal);
Tree root = new TreeNode(rootVal);
root->right = createTree(rootIdxIn + 1, r, rootIdxPost);
root->left = createTree(l, rootIdxIn - 1, rootIdxPost);
return root;
}
void level(Tree root)
{
if (root == NULL)
return;
queue<Tree> q;
printf("%d", root->val);
if (root->left)
q.push(root->left);
if (root->right)
q.push(root->right);
while (!q.empty())
{
Tree p = q.front();
q.pop();
printf(" %d", p->val);
if (p->left)
q.push(p->left);
if (p->right)
q.push(p->right);
}
}
int main()
{
scanf("%d", &N);
for (int i = 0; i < N; i++)
{
scanf("%d", &postorder[i]);
}
for (int i = 0; i < N; i++)
{
scanf("%d", &inorder[i]);
}
int rootIdxPost = N - 1;
Tree root = createTree(0, N - 1, rootIdxPost);
level(root);
}
markdown写bolg,"那是真的niubility"。
[算法笔记] PAT-ADV-1020的更多相关文章
- 学习Java 以及对几大基本排序算法(对算法笔记书的研究)的一些学习总结(Java对算法的实现持续更新中)
Java排序一,冒泡排序! 刚刚开始学习Java,但是比较有兴趣研究算法.最近看了一本算法笔记,刚开始只是打算随便看看,但是发现这本书非常不错,尤其是对排序算法,以及哈希函数的一些解释,让我非常的感兴 ...
- 算法笔记--数位dp
算法笔记 这个博客写的不错:http://blog.csdn.net/wust_zzwh/article/details/52100392 数位dp的精髓是不同情况下sta变量的设置. 模板: ]; ...
- 算法笔记--lca倍增算法
算法笔记 模板: vector<int>g[N]; vector<int>edge[N]; ][N]; int deep[N]; int h[N]; void dfs(int ...
- 算法笔记--STL中的各种遍历及查找(待增)
算法笔记 map: map<string,int> m; map<string,int>::iterator it;//auto it it = m.begin(); whil ...
- 算法笔记--priority_queue
算法笔记 priority_queue<int>que;//默认大顶堆 或者写作:priority_queue<int,vector<int>,less<int&g ...
- 算法笔记--sg函数详解及其模板
算法笔记 参考资料:https://wenku.baidu.com/view/25540742a8956bec0975e3a8.html sg函数大神详解:http://blog.csdn.net/l ...
- 算法笔记——C/C++语言基础篇(已完结)
开始系统学习算法,希望自己能够坚持下去,期间会把常用到的算法写进此博客,便于以后复习,同时希望能够给初学者提供一定的帮助,手敲难免存在错误,欢迎评论指正,共同学习.博客也可能会引用别人写的代码,如有引 ...
- 算法笔记_067:蓝桥杯练习 算法训练 安慰奶牛(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 Farmer John变得非常懒,他不想再继续维护供奶牛之间供通行的道路.道路被用来连接N个牧场,牧场被连续地编号为1到N.每一个牧场都是 ...
- 算法笔记(c++)--回文
算法笔记(c++)--回文 #include<iostream> #include<algorithm> #include<vector> using namesp ...
- 算法笔记(c++)--完全背包问题
算法笔记(c++)--完全背包和多重背包问题 完全背包 完全背包不同于01背包-完全背包里面的东西数量无限 假设现在有5种物品重量为5,4,3,2,1 价值为1,2,3,4,5 背包容量为10 # ...
随机推荐
- EventBus 及一些思考
EventBus 是 Android 开发的一种常用框架,其解耦的思维令人赞叹 从特性上来讲,其与 Android SDK中的BroadcastReceiver很像,二者都是注册,发送事件,反注册,都 ...
- Java中如何更优雅的处理空值
经常看到项目中存在到处空值判断的情况,这些判断,会让人觉得摸不着头绪,它的出现很有可能和当前的业务逻辑并没有关系.但它会让你很头疼.有时候,更可怕的是系统因为这些空值的情况,会抛出空指针异常,导致业务 ...
- 用table类型布局一个新闻网页
<html><head><meta http-equiv="Content-Type" content="text/html; charse ...
- JS面试准备二
1.常用的字符串方法 1. indexOf:查找字符串某一项的初始位置2. slice:截取字符串(包含起始位置,不包含结束位置) 不会根据参数大小,交换参数位置 如果出现-1按倒数第一个数,如果出现 ...
- 微信小程序学习简介
如何向微信小程序导入DEMO源码: 参考方法 参考学习小程序官方文档 小程序官方文档 小程序目录简介 app.json :设置一些工程全局的量.js : 写一些函数逻辑.wxml: 调用.js中写的函 ...
- JS基础入门篇(十八)—日期对象
1.日期对象 日期对象: 通过new Date()就能创建一个日期对象,这个对象中有当前系统时间的所有详细信息. 以下代码可以获取当前时间: <script> var t = new Da ...
- xml模块介绍
# xml 是一门可拓展的语言 # xml 语法 是用<>包裹的起来的<>就是标签, xml可以由多个<>组成 也可以由单个<>组成, # < ...
- redis如何在spring里面的bean配置
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.spr ...
- 打造你的第一个 Electron 应用
Electron 可以让你使用纯 JavaScript 调用丰富的原生(操作系统) APIs 来创造桌面应用. 你可以把它看作一个 Node. js 的变体,它专注于桌面应用而不是 Web 服务器端. ...
- springboot项目中接口入参的简单校验
.katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...