根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
自己AC的代码没了辣鸡LeetCode吞代码就找了个别人博客的,思想是完全一样的
/**
* 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)
{
return buildTree(preorder, inorder, 0, preorder.size() - 1, 0, inorder.size() - 1);
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder, int preStart, int preEnd, int inStart, int inEnd)
{
//不要|| inStart > inEnd这个条件也是可以AC的,自己写的没有加
if (preStart > preEnd || inStart > inEnd)
return NULL;
TreeNode *res;
res = new TreeNode(preorder[preStart]);
int flag;
for (int i = inStart; i <= inEnd; i++)
{
if (preorder[preStart] == inorder[i])
{
flag = i;
break;
}
}
//flag - inStart是左子树(在数组中的)长度,这样就好理解很多了
res->left = buildTree(preorder, inorder, preStart+1, preStart+flag-inStart, inStart, flag-1);
res->right = buildTree(preorder, inorder, preStart+flag-inStart+1, preEnd, flag+1, inEnd);
return res;
}
};
可以看出,前序遍历的第一个节点就是根节点,在中序中找到这个节点即可将其分为左子树和右子树,很明显对左右子树的处理与之相同,因此要递归处理,但怎么递归这个东西就比较麻烦。
一开始想每次都用新数组(vector)来存,后来觉得这样拷贝stl容器费时费空间于是就没有这样做,想到了重写一个函数,参数增加数组的开始和结束点来处理。
preStart和preEnd指前序遍历数组的始末点,inStart和inEnd则是中序遍历数组的,需要注意的事flag-instart才是左子树(在数组中的)长度,而不是flag,之前一直写flag错了很多遍,其他的起始和终止下标较容易理解不做赘述。
虽说题目不太难,但可能因为还没学过数据结构还是花了好久才写出来。
补充:根据中序和后序建立二叉树
/**
* 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 buildTree(inorder, postorder, 0, inorder.size() - 1, postorder.size() - 1, 0);
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder, int inStart, int inEnd, int postEnd, int postStart)
{
if (inStart > inEnd || postEnd < postStart)
{
return NULL;
}
int flag;
TreeNode *res = new TreeNode(postorder[postEnd]);
for(int i=inStart;i<=inEnd;i++)
{
if(postorder[postEnd]==inorder[i])
{
flag=i;
break;
}
}
res->right=buildTree(inorder,postorder,flag+1,inEnd,postEnd-1,postEnd-(inEnd-flag));
res->left=buildTree(inorder,postorder,inStart,flag-1,postEnd-(inEnd-flag)-1,postStart);
return res;
}
};
与之思想类似,不过根据后序建立的顺序则应该是从后向前的,后序遍历的数组从后向前依次为根节点,右子树的根节点和左子树的根节点,而前序数组则是从前往后依次为根节点,左子树根节点和右子树根节点,相应改变递归参数即可,此时inEnd-flag为右子树(在数组中的)长度。