1,题目要求
Return any binary tree that matches the given preorder and postorder traversals.
Values in the traversals pre and post are distinct positive integers.
根据先序遍历和后序遍历的结果,构造一颗满足条件的树。
2,题目思路
对于这道题,首先需要思考的是,如果仅仅是在纸面上去构建这样的树,应该怎样去创建?
这里就需要对先序遍历和后序遍历的各自特点进行分析了。
对于先序遍历而言,最先遍历的一定是根节点,然后分别是左右子树,因此,遍历的结果如下图所示:
[root][…left…][…right…]
而对于后序遍历,则类似的,最后去遍历的才是根节点,因此:
[…left…][…right…][root]
因此,我们要找到的就是这样的left和right部分,即找到他们分别的开始位置以及结束位置。
首先,我们对后序遍历的结果进行映射(value -> index),这样,我们就可以根据在前序遍历中找到的值,找到后序遍历里的对应的值所在后序遍历结果中的位置。
就像题目中所示,
先序遍历:[1][2,4,5][3,6,7]
后序遍历:[4,5,2][6,7,3][1]
对于先序遍历中的2,后续中它正好就是left的最后一个元素,因此,这个index - postStart就是left的长度。
同样的,也可以很轻松的找到right的长度、在pre和post里的开始位置和结束位置。
3,程序源码
class Solution {
public:
TreeNode* constructFromPrePost(vector<int>& pre, vector<int>& post) {
int len = pre.size();
for(int i = 0;i<len;i++)
m[post[i]] = i; //对后序遍历进行value -> index的映射
return coHelper(pre, post, 0, len-1, 0, len-1);
}
TreeNode* coHelper(vector<int>& pre, vector<int>& post, int preStart, int preEnd, int postStart, int postEnd)
{
if(preStart>preEnd) return nullptr;
TreeNode* root = new TreeNode(pre[preStart]); //作为左右子树的划分位置
if(preStart == preEnd) return root;
int idx = m[pre[preStart+1]]; //先序遍历中,左子树的第一个节点在后序遍历的列表中的位置
int offset = idx - postStart; //表示左子树的长度(节点的数量),设定一个偏移量来进行表示
root->left = coHelper(pre, post, preStart+1, preStart+1+offset, postStart, idx);
root->right = coHelper(pre, post, preStart+1+offset+1, preEnd, idx+1, postEnd);
return root;
}
private:
unordered_map<int, int> m;//对于post内的值和其索引进行映射
};