腊月了,最近开始学习二外(日语)、提升身体素质(靠墙蹲、平板支撑),当然,也心情好到开始刷题~
题目描述:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
(这是牛客网提供的一道题目,想尝试的码友们,可以通过这个链接挑战https://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6?tpId=188&&tqId=37520&rp=1&ru=/activity/oj&qru=/ta/job-code-high-week/question-ranking)
我们将按照⑤个步骤拆解此题
步骤① --题目分析
把题目描述翻译成程序员能听懂的话,就是给出二叉树前序遍历和中序遍历,构建这棵二叉树。
步骤② --根据前序和中序建树
(已经可以熟练建树的码友,可以跳过步骤②)
建树步骤其实是一个逐步分解的递归过程
首先,明确概念,前序遍历是按照根节点-->左子节点-->右子节点的顺序遍历一棵树;中序遍历是按照左子节点--> 根节点-->右子节点的顺序遍历一棵树。
下图来模拟这个建树过程。
其中,t用来记录当前根节点在中序遍历中位于第几个。
步骤③ --递归中一次动作分析
由步骤②可知,本题是由若干次重复动作组成的,这个动作是:(1)找到根节点的值和位置,建立根节点;(2)将前序遍历拆分为左子前序遍历和右子前序遍历;将中序遍历拆分为左子中序遍历和右子中序遍历;(3)对左子前序遍历和左子中序遍历调函数;对右子前序遍历和右子中序遍历调函数。
步骤④ --C++代码分析
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
vector<int>::iterator i, j;
TreeNode *root;
int t;
if(pre.size() > 0)
{
root = new TreeNode(NULL); /*(1)建立根节点*/
root->val = *pre.begin();/*(1)找到根节点的值*/
if(pre.size() > 1)
{
int root_num = pre.front();
int root_sit;
t = 0;
for(i = vin.begin(); i < vin.end(); i++)/*(1)找到根节点的位置*/
{
t++;
if(*i == root_num)
{
root_sit = *i;
break;
}
}
std::vector<int>::const_iterator first1 = pre.begin() + 1;
std::vector<int>::const_iterator last1 = pre.begin() + t;
std::vector<int> pre_newl (first1, last1); /*(2)将前序遍历拆分为左子前序遍历*/
std::vector<int>::const_iterator first2 = vin.begin();
std::vector<int>::const_iterator last2 = vin.begin() + t -1;/*坑一*/
std::vector<int> vin_newl (first2, last2); /*(2)将中序遍历拆分为左子中序遍历*/
root->left = reConstructBinaryTree(pre_newl, vin_newl);/*(3)对左子前序遍历和左子中序遍历调函数*/
std::vector<int>::const_iterator first3 = pre.begin() + t;
std::vector<int>::const_iterator last3 = pre.end();
std::vector<int> pre_newr (first3, last3); /*(2)将前序遍历拆分为右子前序遍历*/
std::vector<int>::const_iterator first4 = vin.begin() + t;
std::vector<int>::const_iterator last4 = vin.end();
std::vector<int> vin_newr (first4, last4); /*(2)将中序遍历拆分为右子中序遍历;*/
root->right = reConstructBinaryTree(pre_newr, vin_newr); /*(3)对右子前序遍历和右子中序遍历调函数。*/
}
}
else
{
root = NULL;/*坑二*/
}
return root;
}
};
步骤⑤ --反思踩过的坑
代码更新完善两版后,才顺利AC了,将发现并解决坑时的测试数据贴出来,与码友们共同反思。
坑一
前序遍历[1,2,4,8,9,5,10,11,3,6,12,13,7,14,15]
中序遍历[8,4,9,2,10,5,11,1,12,6,13,3,14,7,15]
建树为[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
反思 注意将遍历拆分为左子遍历和右子遍历时,拆分点的计算。
坑二
前序遍历[1,2,4,3,5,6]
中序遍历[4,2,1,5,3,6]
建树为[1,2,3,4,#,5,6]
反思 注意空节点的处理,树不一定是满树。