题目大意
给出一棵二叉树的前序和中序遍历,构建出原来的二叉树(题目保证给定的节点值不会重复)
解题思路
不得不说这题的思路确实是简单粗暴。众所周知,前序遍历的顺序是中左右,设其结果为Preorder,而中序遍历是左中右,设其结果为Inorder,那么可以知道前序遍历结果的首个节点位置k必为中间节点,那么在Inorder中找到该节点的位置kk,Inorder首节点到kk这一段为左子树,kk+1到Inorder的尾巴为右子树,使用递归重复上述过程重复建立树节点即可。
另外一道已知中序和后序的题目也是同样的思路,只需要在截取遍历结果的时候稍加改动即可。
总结
题目不难,思路也很清晰,重点就在于两个细节:
1、为避免OJ判断MLE,考虑传入STL的vector迭代器作为参数参与递归,因为在实际编译运行时,其实参需要一一入栈,如果将vector本身传递进函数,则每递归一次就要将vector入栈,因此将消耗大量的空间,因此使用迭代器指向其首位置传入能避免上述问题。
2、使用相对距离而不是绝对位置,每次从当前两个序列截取时一定要使用相对的变更长度而非直接取到数组的下标位置,因为两种序列的下标基址不在同一位置。
代码
//遍历store,返回elem元素的位置
int find(vector<int>::iterator store, int left, int right, int elem)
{
int i = 0;
for (int i = left; i <= right; ++ i){
if (elem == *(store+i))return i;
}
return -1;
}
void dfs(vector<int>::iterator A, int leftA, int rightA, vector<int>::iterator B, int leftB, int rightB, TreeNode *&cur)
{
if (leftA > rightA || leftB > rightB)return ;
cur = new TreeNode(A[leftA]);
if (leftA == rightA || leftB == rightB)return ;
int midA = find(A, leftA, rightA, *(B+leftB));
int midB = find(B, leftB, rightB, *(A+leftA));
dfs(A, leftA+1, leftA+midB-leftB, B, leftB, midB-1, cur->left);//注意这里用相对长度!!
dfs(A, leftA+midB-leftB+1,rightA, B, midB+1, rightB, cur->right);//注意这里用相对长度!!
/*Construct Binary Tree from Inorder and Posteorder Traversal
dfs(A, leftA, midA-1, B, leftB, leftB+midA-leftA-1, cur->left);
dfs(A, midA+1,rightA, B, leftB+midA-leftA, rightB-1, cur->right); */
return ;
}
TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder)
{
TreeNode *root = NULL;
dfs( preorder.begin(), 0, preorder.size()-1, inorder.begin(), 0, inorder.size()-1, root);
return root;
}