题目地址:
https://www.acwing.com/problem/content/description/1261/
树和二叉树基本上都有先序、中序、后序、按层遍历等遍历顺序,给定中序和其它一种遍历的序列就可以确定一棵二叉树的结构。假定一棵二叉树一个结点用一个字符描述,现在给出中序和按层遍历的字符串,求该树的先序遍历字符串。
输入格式:
两行,每行是由大写字母组成的字符串(一行的每个字符都是唯一的),分别表示二叉树的中序遍历和按层遍历的序列。
输出格式:
一行,表示二叉树的先序序列。
数据范围:
输入字符串的长度均不超过
26
26
26。
给定层序遍历 t t t之后,首先知道 t [ 0 ] t[0] t[0]是树根,我们可以根据层序遍历来把整棵树构造出来。在遍历 t t t的时候构造整棵树,缺乏的是不知道当前遍历到的节点是左孩子还是右孩子,这个时候中序遍历就起到了作用,我们只需要看当前节点在中序遍历的位置,如果这个位置左边还有没遍历过的元素,则说明当前节点是左孩子,否则是右孩子。同时需要在中序遍历中标记一下当前节点用过了。构造完整棵树之后再前序遍历一遍即可。代码如下:
#include <iostream>
#include <cstring>
#include <queue>
#include <unordered_map>
using namespace std;
const int N = 50;
int l[N], r[N], idx;
string sin, slevel;
unordered_map<char, int> mp;
bool vis[N];
void dfs(int u) {
if (~u) {
cout << slevel[u];
dfs(l[u]);
dfs(r[u]);
}
}
int main() {
memset(l, -1, sizeof l);
memset(r, -1, sizeof r);
cin >> sin >> slevel;
for (int i = 0; i < sin.size(); i++) mp[sin[i]] = i;
queue<int> q;
q.push(0);
while (q.size()) {
int t = q.front(); q.pop();
int k = mp[slevel[t]];
vis[k] = true;
// 判断++idx是不是左孩子
if (k && !vis[k - 1]) {
l[t] = ++idx;
q.push(idx);
}
// 判断++idx是不是右孩子
if (k < sin.size() - 1 && !vis[k + 1]) {
r[t] = ++idx;
q.push(idx);
}
}
dfs(0);
}
时空复杂度 O ( n ) O(n) O(n), n n n为字符串长度。