Leetcode105. 从前序与中序遍历序列构造二叉树
题目描述
根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
1 2
| 前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = [9,3,15,20,7]
|
返回如下的二叉树:
解题思路
这道题我们可以运用递归写出非常简洁和通俗易懂的代码,需要注意递归时函数参数的设定。
在求解的过程中,我们主要利用了前序遍历和中序遍历的性质:
对于任意一颗树而言,前序遍历的形式总是:
[ 根节点, [左子树的前序遍历结果], [右子树的前序遍历结果] ]
即根节点总是前序遍历中的第一个节点。因此,我们总是可以通过前序遍历找到根节点。
而中序遍历的形式总是:
[ [左子树的中序遍历结果], 根节点, [右子树的中序遍历结果] ]
可以看到的是,在中序遍历序列中,在根节点左端的都是左子树的中序遍历结果,在根节点右端的都是右子树的中序遍历结果。只要我们在中序遍历中找到根节点的位置,那么我们就可以确定左子树和右子树的结点数目。
因此,我们先可以通过先序遍历找出根节点,然后再通过中序遍历来确定左子树的结点数目。这样一来,我们就确定了一棵树的根节点,左子树的结点数目和右子树的结点数目。接着递归地构造左子树和右子树直到递归出口——当前序遍历或者中序遍历的数组为空时,返回nullptr
指针。这样就最终构建了整颗树。
示例代码如下。
示例代码
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 28 29 30 31 32 33 34 35 36 37 38 39
| struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode() : val(0), left(nullptr), right(nullptr) {} TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} };
unordered_map<int,int>index;
TreeNode* myBuildTree(vector<int>& preorder, vector<int>& inorder,int preorder_left,int preorder_right,int inorder_left,int inorder_right) { if(preorder_left>preorder_right) return nullptr; int preorder_root=preorder[preorder_left]; int inorder_root_index=index[preorder_root]; int size_left_subtree=inorder_root_index-inorder_left; TreeNode* root=new TreeNode(preorder_root);
root->left=myBuildTree(preorder,inorder,preorder_left+1,preorder_left+size_left_subtree,inorder_left,inorder_root_index-1); root->right=myBuildTree(preorder,inorder,preorder_left+size_left_subtree+1,preorder_right,inorder_root_index+1,inorder_right);
return root; }
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { for(int i=0;i<inorder.size();++i) { index[inorder[i]]=i; } return myBuildTree(preorder,inorder,0,preorder.size()-1,0,inorder.size()-1); }
|