原题链接:105. 从前序与中序遍历序列构造二叉树
题目
题解:
先写代码:(讲解代码即讲解思路)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
map<int,int> f;
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
for (int i = 0; i < preorder.size(); i++) f[inorder[i]] = i;
TreeNode* root = dfs(0, inorder.size()-1, 0, preorder.size()-1, preorder);
return root;
}
TreeNode* dfs(int is, int ie, int ps, int pe, vector<int> pre) {
if (ie < is || pe < ps) return nullptr;
TreeNode* cur = new TreeNode();
cur->val = pre[ps];
int ri = f[pre[ps]];
cur->left = dfs(is, ri-1, ps+1, ps+ri-is, pre);
cur->right = dfs(ri+1, ie, ps+ri-is+1, pe, pre);
return cur;
}
};
前序是根左右,中序是左根右。使用递归逐步构造左右子树。

我们在前序序列中找到一个根之后,在中序序列中以根为分界点分为左子树和右子树,然后递归构建左子树和右子树。对于我们当前在前序序列中找到的点n,它便是当前子树的根节点。
递归函数dfs参数解释:下面说的子树是指左子树或者是右子树
- is 表示子树在中序序列中的起始位置
- ie 表示子树在中序序列中的结束位置
- ps 表示子树在前序序列中的起始位置
- pe 表示子树在前序序列中的结束位置
- pre 表示前序序列
递归函数的关键便是这些位置下标的计算,例如在图1中,当我们在前序序列中找到一个根3时,接着我们在中序序列中找到他的位置,记为ri,我们首先可以确定以3为根的子树的左子树在中序序列中的范围为:[is, ri-1];右子树的范围为:[ri+1, ie];
如何在前序序列中确定左子树、右子树的范围呢?首先,前序序列中左子树的开始坐标为ps+1,这不难理解。左子树的结束坐标是根据左子树的大小确定的。因为我们在中序序列中已经知道左子树的范围为:[is, ri-1],那么左子树中节点的个数为:ri-is。那么前序序列中左子树的结束坐标就是:开始坐标+左子树节点个数-1,即:ps+ri-is。所以左子树在前序序列中范围为:[ps+1, ps+ri-is]。
所以我们算出了以3为根节点的左子树的递归函数的所有参数:
dfs(is, ri-1, ps+1, ps+ri-is, pre)
同理,右子树在前序序列的开始坐标是:左子树的结束坐标+1,即ps+ri-is+1;结束坐标是pe。所以右子树的递归函数为:
dfs(ri+1, ie, ps+ri-is+1, pe, pre)
至此,我们解决了最关键的问题。
还有一个,在前序序列中找到了根节点,如何快速求出他在中序序列中的下标,这里用到了map映射,原理很简单,直接看代码应该就能理解,不再详细解释。
这道题和105是一样的,我们只要重新计算一下区间即可:
root->left = dfs_inAndPost(is, ri - 1, ps, pe+ri-ie-1, postorder);
root->right = dfs_inAndPost(ri + 1, ie, pe + ri - ie, pe - 1, postorder);
北理工复试上机题目
将这两道题结合起来就是2024年北京理工大学计算机专业复试机试最后一道题目,原题目大致题意如下:给出前序、中序输出后序;或者给出中序、后续输出前序遍历。原题目输入的是大写字母,这两道题输入的是数字,不影响解题。
将这两道题目的代码结合起来就是复试最后一道题目的题解:
#include <bits/stdc++.h>
using namespace std;
vector<int> preorder;
vector<int> inorder;
vector<int> postorder;
map<int,int> f;
// 定义二叉树节点结构体
struct TreeNode {
// 节点存储的整型数值
int value;
// 指向左孩子的指针
TreeNode* left;
// 指向右孩子的指针
TreeNode* right;
// 构造函数
TreeNode(int val) : value(val), left(nullptr), right(nullptr) {}
};
TreeNode* dfs_inAndpre(int is, int ie, int ps, int pe, vector<int>& preorder) {
if (is > ie || ps > pe) return nullptr;
TreeNode* root = new TreeNode(preorder[ps]);
int ri = f[root->value];
root->left = dfs_inAndpre(is, ri - 1, ps + 1, ps + ri - is, preorder);
root->right = dfs_inAndpre(ri + 1, ie, ps + ri - is + 1, pe, preorder);
return root;
}
TreeNode* dfs_inAndpost(int is, int ie, int ps, int pe, vector<int>& postorder) {
if (is > ie || ps > pe) return nullptr;
TreeNode* root = new TreeNode(postorder[pe]);
int ri = f[root->value];
root->left = dfs_inAndpost(is, ri - 1, ps, pe+ri-ie-1, postorder);
root->right = dfs_inAndpost(ri + 1, ie, pe+ri-ie, pe - 1, postorder);
return root;
}
void printTree_pre(TreeNode* root) {
if (root == nullptr) return;
cout << root->value << " ";
printTree_pre(root->left);
printTree_pre(root->right);
}
void printTree_post(TreeNode* root) {
if (root == nullptr) return;
printTree_post(root->left);
printTree_post(root->right);
cout << root->value << " ";
}
int main()
{
int flag;
cout << "1、输入中序、前序;2、输入中序、后序;" << endl;
cin >> flag;
int n;
cin >> n;
if (flag == 1) {
for (int i = 0; i < n; i++) {
int temp;
cin >> temp;
inorder.push_back(temp);
}
for (int i = 0; i < n; i++) {
int temp;
cin >> temp;
preorder.push_back(temp);
}
for (int i = 0; i < n; i++) f[inorder[i]] = i;
TreeNode* root = dfs_inAndpre(0, n - 1, 0, n - 1, preorder);
printTree_post(root);
} else {
for (int i = 0; i < n; i++) {
int temp;
cin >> temp;
inorder.push_back(temp);
}
for (int i = 0; i < n; i++) {
int temp;
cin >> temp;
postorder.push_back(temp);
}
for (int i = 0; i < n; i++) f[inorder[i]] = i;
TreeNode* root = dfs_inAndpost(0, n - 1, 0, n - 1, postorder);
printTree_pre(root);
}
}
已经忘记当时怎么做的了,只通过了两个测试样例。但是幸亏前都三个题目都ac了。