题目要求:给出二叉树的后序遍历序列和中序遍历序列,输出二叉树的层次遍历序列。

传送门

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 4 5 6 7

也就是说可以得到二叉树的基本结构如下:

图1
4
/ \
1,2,3 5,6,7

再看后序序列剩下的元素:

2 3 1 5 7 6

最后一个元素是 6, 说明在 6 是根。

在中序序列中:

1 2 3 | 4 | 5 6 7

说明在 图1 中, 6 是右子树的根。

图2
4
/ \
1,2,3 6
/ \
5 7

继续遍历后序序列:

2 3 1 5 7

5 和 7 既是叶子节点也是一个特殊的根。

此时,后序序列剩下:

2 3 1

中序序列为:

1 2 3

显然, 1 是根, 2 和 3 是 1 的右子树。以此类推, 2 是 3 的左子树。那么中序序列和后序序列唯一确定的二叉树如下:

         4
/ \
1 6
\ / \
3 5 7
/
2

概括一下算法要点:

  • 从右往左遍历后序序列,得到根
  • 在中序序列中找到根,分离出左右子树
  • 对左右子树进行同样的操作

不难看出,是一个递归。

数据结构课程上,在纸上这类题目大家都会画出来,但是一到 Code 层面,完整实现还是有点难度的。

最后解析一下代码实现。

  • 参数 lr: 中序序列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的更多相关文章

  1. 学习Java 以及对几大基本排序算法(对算法笔记书的研究)的一些学习总结(Java对算法的实现持续更新中)

    Java排序一,冒泡排序! 刚刚开始学习Java,但是比较有兴趣研究算法.最近看了一本算法笔记,刚开始只是打算随便看看,但是发现这本书非常不错,尤其是对排序算法,以及哈希函数的一些解释,让我非常的感兴 ...

  2. 算法笔记--数位dp

    算法笔记 这个博客写的不错:http://blog.csdn.net/wust_zzwh/article/details/52100392 数位dp的精髓是不同情况下sta变量的设置. 模板: ]; ...

  3. 算法笔记--lca倍增算法

    算法笔记 模板: vector<int>g[N]; vector<int>edge[N]; ][N]; int deep[N]; int h[N]; void dfs(int ...

  4. 算法笔记--STL中的各种遍历及查找(待增)

    算法笔记 map: map<string,int> m; map<string,int>::iterator it;//auto it it = m.begin(); whil ...

  5. 算法笔记--priority_queue

    算法笔记 priority_queue<int>que;//默认大顶堆 或者写作:priority_queue<int,vector<int>,less<int&g ...

  6. 算法笔记--sg函数详解及其模板

    算法笔记 参考资料:https://wenku.baidu.com/view/25540742a8956bec0975e3a8.html sg函数大神详解:http://blog.csdn.net/l ...

  7. 算法笔记——C/C++语言基础篇(已完结)

    开始系统学习算法,希望自己能够坚持下去,期间会把常用到的算法写进此博客,便于以后复习,同时希望能够给初学者提供一定的帮助,手敲难免存在错误,欢迎评论指正,共同学习.博客也可能会引用别人写的代码,如有引 ...

  8. 算法笔记_067:蓝桥杯练习 算法训练 安慰奶牛(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 问题描述 Farmer John变得非常懒,他不想再继续维护供奶牛之间供通行的道路.道路被用来连接N个牧场,牧场被连续地编号为1到N.每一个牧场都是 ...

  9. 算法笔记(c++)--回文

    算法笔记(c++)--回文 #include<iostream> #include<algorithm> #include<vector> using namesp ...

  10. 算法笔记(c++)--完全背包问题

    算法笔记(c++)--完全背包和多重背包问题 完全背包 完全背包不同于01背包-完全背包里面的东西数量无限 假设现在有5种物品重量为5,4,3,2,1  价值为1,2,3,4,5  背包容量为10 # ...

随机推荐

  1. HTML标签学习总结(3)

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...

  2. C++走向远洋——24(项目一,三角形,复制构造函数)

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:sanjiaoxing.cpp * 作者:常轩 * 微信公众号: ...

  3. 死磕Lambda表达式(二):Lambda的使用

    城市就是森林,每一个男人都是猎手,每一个女人都是陷阱.--<三体> 在哪使用Lambda表达式? 在上一篇文章(传送门)中介绍了Lambda表达式的基本语法,其中的举了一个Lambda表达 ...

  4. 什么是Activiti

    什么是Activiti Activiti属于工作流引擎的一个开源实现.Activiti由Tom Bayen发起.在2010年5月发布了第一个版本.命名也很有意思的采取了Activities(活动)的化 ...

  5. css自定义 range radio select的样式滑轮,按钮,选择框

    写在前面: 之前踩坑css的时候,遇到滑轮,按钮,选择框这类型的东西,为了页面效果,总是需要自定义他们的样式,而不使用他们的默认样式.当时写的时候,我也是蛮头疼的,弄了个demo,链接在下面.对此做个 ...

  6. Django中的session的使用

    一.Session 的概念 cookie 是在浏览器端保存键值对数据,而 session 是在服务器端保存键值对数据 session 的使用依赖 cookie:在使用 Session 后,会在 Coo ...

  7. python虚拟环境安装使用

    # 安装 pip install virtualenv pip install virtualenvwrapper-win # win环境下 liunx下不需要-win #创建一个文件夹并cd进去mk ...

  8. selenium 爬boss

    # 有问题 from selenium import webdriver import time from lxml import etree class LagouSpider(object): d ...

  9. JAVAEE学习day02

    1.数据类型的转换 1>自动转换(隐式) // 将取值范围小的数据类型自动提升为取值范围大的类型 // 定义byte类型数据 byte b = 10; // 定义short类型数据 short ...

  10. nginx升级不改变配置文件

    查看当前版本是:1.10.3 [root@proxy nginx-1.10.3]# /usr/local/nginx/sbin/nginx -Vnginx version: nginx/1.10.3b ...