题目来源
https://leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/
题目描述
Given inorder and postorder traversal of a tree, construct the binary tree.
Note:
You may assume that duplicates do not exist in the tree.
For example, given
inorder = [9,3,15,20,7]
postorder = [9,15,7,20,3]
Return the following binary tree:
题意分析
给出一棵二叉树的中序遍历数组和后序遍历数组,还原这课二叉树。
前序知识
相信能看到这篇博客的你们一定已经知道二叉树、中序遍历和后序遍历(当然还有先序遍历)是什么。
假设我们有如下一棵二叉树:
它的中序遍历数组数是 [4,2,5,1,6,3,7]
,它的后序遍历数组数是 [4,5,2,6,7,3,1]
。
经过观察,我们应该能发现:
- 中序遍历数组的根结点元素“1”的左边的数组([4,2,5])是根结点左子树的中序遍历数组,右边的数组([6,3,7])是根结点右子树的中序遍历数组。
- 后序遍历数组的最后那个元素是根结点元素“1”,左子树数组是除最后一个元素(根结点)外靠前的部分([4,5,2]),右子树数组是靠后的那部分([6,7,3])。
于是我们可以总结:
- 中序遍历数组的结构是:若一个数组表示一个二叉树,那么数组中有一个元素是根结点,在根节点的左边的数组是左子树数组,在根结点右边的数组是右子树数组。这个根结点元素在哪?需要有额外信息确定,比如后序遍历数组的最后一个元素(或者先序遍历的第一个元素)。
- 后序遍历数组的结构是:若一个数组表示一棵二叉树,那么最后一个元素是根结点,左子树数组是除最后一个元素(根结点)外靠前的部分,右子树数组是靠后的那部分。
题目思路
所以本题的思路可以是:用后序遍历数组的最后一个元素确定二叉树的根结点元素root_val
,然后使用这个元素找到它在中序遍历数组的位置inindex
,(中序遍历数组下标从instart
到inend
)从而确定左右子树的中序遍历数组;同时利用左右子树中序遍历数组的长度确定左右子树后序遍历数组,最后将问题划分成“找左右子数组的根结点”的递归问题。
加粗部分要怎么做呢?右子树长度是inend-inindex
,那么后序遍历数组(后序遍历数组最后一个元素的下标是postend
)的右子树的最后一个元素的下标是postend-1
,左子树的最后一个元素下标是postend-1-(inend-instart)
。
对于后序遍历数组,我们这需要知道它的结束部分postend
。因为结束部分是它所在子树数组的根结点,而它的poststart并没有什么卵用。
做递归还需要有终止条件,认为instart>inend
就是终止条件。
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
return helper(inorder, postorder, 0, inorder.size()-1, postorder.size()-1);
}
TreeNode* helper(vector<int> &inorder, vector<int> &postorder, int instart, int inend, int postend) {
if(instart>inend) { //终止条件
return NULL;
}
int root_val = postorder[postend]; //从后序遍历数组的最后一个元素获得当前树的根结点
int inindex;
for(int i=instart; i<=inend; i++) { //相应得到中序遍历数组中根结点位置
if(root_val == inorder[i]) {
inindex = i;
}
}
TreeNode* right = helper(inorder, postorder, inindex+1, inend, postend-1); // 构建右子树
TreeNode* left = helper(inorder, postorder, instart, inindex-1, postend-1-(inend-inindex)); // 构建左子树
TreeNode* root = new TreeNode(root_val);
root->left = left;
root->right = right;
return root; //返回构建好的树
}
};
你的赞或关注都是对博主莫大的激励!