题目
Given preorder and inorder traversal of a tree, construct the binary tree.
Note:
You may assume that duplicates do not exist in the tree.
For example, given
preorder = [3,9,20,15,7]
inorder = [9,3,15,20,7]
Return the following binary tree:
3
/ \
9 20
/ \
15 7
题目要求是利用二叉树的先序和中序遍历的数组,来构建二叉树。
如果不了解二叉树的先序和中序遍历的话,别人的博客都有介绍可以先了解下。这里我们直接以知道遍历方法来讲述。
树的先序遍历先输出树的根节点,再输出左子节点,再输出右子节点。
树的中序遍历则是先输出左子节点,再输出根节点,最后输出右子节点。
我们先由例子来找规律,由先序遍历的数组开始一个一个来,首先是3,由于先序遍历是先输出根节点的,所以先序遍历数组的第一个元素便是这棵二叉树的根节点,即根节点是3。
然后我们看到3在中序遍历数组的第2个元素的位置,我们知道树的中序遍历先输出左子节点,再输出根节点,通俗的说就是先左,再中,后右。那么在3之前输出的就属于3的左子树,在3后面则属于3的右子树。所以由中序遍历数组我们可以初步得到以下树形:
3
/ \
(9)(15,20, 7)
此时我们看先序遍历数组的第二个元素,第二个元素是9,也就是说9是3的左子树的根节点,此时3的左子树也只有9。所以此时左边结束。
3
/ \
9 (15,20,7)
接下来我们看先序遍历数组的第三个元素,是20,也就是说20是3的右子树的根节点,那么我们再看20在中序遍历数组的位置,此时我们需要确定是3的右子树,所以只需要看3的右子树部分的数字,也就是看15,20,7这3个数的相对位置,可以看到15在20前输出(在20左边),7在20之后(在20后边),也就是说,15是以20为根节点的左子树的部分,而7则是以20为根节点的右子树的部分。
此时我们便已得出我们所需要的二叉树了。
3
/ \
9 20
/ \
15 7
总结一下步骤就是:
- 从头到尾依次拿出先序遍历数组的一个元素,设为A。
- 确定该元素A在中序遍历数组的位置。在中序遍历数组中,位于元素A的左边的元素则在树中属于元素A的左子树,位于元素A的右边的元素则在树中属于元素A的左子树。
- 重复1,2直至所有元素排列完成。
这种特性用递归的方式就能很好的实现,C++代码如下:
/**
* 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>& preorder, vector<int>& inorder) {
/*利用map来存储树元素在中序遍历数组的位置,
这样取位置的时候不用每次遍历一下数组来获得*/
map<int, int> nodesIndex;
int index = 0;
for (int i = 0; i < inorder.size(); ++i) {
nodesIndex[inorder[i]] = i;
}
if (preorder.size() == 0) return NULL;
TreeNode* head = new TreeNode(preorder[0]);
if (nodesIndex[preorder[0]] > 0) {
helpToBuildTree(preorder, nodesIndex, head, true, ++index, 0,
nodesIndex[preorder[0]] - 1);
}
if (nodesIndex[preorder[0]] < preorder.size() - 1) {
helpToBuildTree(preorder, nodesIndex, head, false, ++index,
nodesIndex[preorder[0]] + 1, preorder.size() - 1);
}
return head;
}
void helpToBuildTree(vector<int>& preorder, map<int, int>& nodesIndex,
TreeNode* node, bool left, int& index, int front, int latter) {
TreeNode* tmp;
if (left) {
node->left = new TreeNode(preorder[index]);
tmp = node->left;
}
else {
node->right = new TreeNode(preorder[index]);
tmp = node->right;
}
int inorderIndex = nodesIndex[preorder[index]];
if (inorderIndex > front) {
helpToBuildTree(preorder, nodesIndex, tmp, true, ++index,
front, inorderIndex - 1);
}
if (inorderIndex < latter) {
helpToBuildTree(preorder, nodesIndex, tmp, false, ++index,
inorderIndex + 1, latter);
}
}
};
跑的速度也不错,在leetcode上跑的时间如下: