本文为剑指 offer 系列第六篇。
主要就是根据二叉树遍历的前序遍历和中序遍历重新构造出原始的二叉树。
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
解题思路
前序遍历的顺序是 根节点,左子树,右子树。
中序遍历的顺序是 左子树,根节点,右子树。
所以我们可以发现,前序遍历的第一个节点就是根节点,然后我们在中序遍历中找到这个根节点,那么这个根节点之前的就是左子树的中序,根节点之后的就是右子树的中序,然后可以根据左子树的个数,在前序遍历中将左子树和右子树进行分离,而分离的结果可以用来构建左子树和右子树。
下面以题目中的数据为例进行详细说明
- 首先根据前序遍历,可以知道当前的根节点为1。
- 在中序遍历中寻找节点1, 然后1之前的节点[4,7,2]就是当前树的左子树的中序遍历,1之后的节点[5,3,8,6]就是当前树的右子树的中序遍历。
- 在前序遍历中根据左子树的节点个数找到对应的左子树的前序遍历[2,4,7],和对应的右子树的前序遍历【3,5,6,8】。
- 同样的操作可以继续针对左子树和右子树,从而把整个的二叉树构建出来。
解题代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| /** * 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) { return helper(pre,0,pre.size()-1,vin,0,vin.size()-1); } TreeNode* helper(vector<int> pre,int pstart,int pend,vector<int> vin,int vstart,int vend){ if(vstart > vend) return NULL; int root = pre[pstart]; TreeNode* temp = new TreeNode(root); auto a = find(vin.begin(),vin.end(),root); int index = distance(vin.begin(),a); int lnum = index - vstart; //左子树 temp -> left = helper(pre,pstart+1,pstart+lnum,vin,vstart,index-1); temp -> right = helper(pre,pstart+1+lnum,pend,vin,index+1,vend); return temp; } };
|
时间复杂度为O(n),空间复杂度为O(n)
类似的题目还有根据中序和后续进行重建二叉树,道理类似,只是根节点变成了后续遍历的最后一个节点。
以上,本题结束!