LeetCode_Construct Binary Tree from Preorder and Inorder Traversal

Given preorder and inorder traversal of a tree, construct the binary tree.

Note:
You may assume that duplicates do not exist in the tree.

题目如上所示:给出二叉树的先序遍历序列和中序遍历序列,复原二叉树。

分析:

1)题目拿过来,首先要清楚二叉树的三种遍历方式:

前序遍历(Preorder),首先访问根节点,然后遍历左子树,最后遍历右子树(根-左-右)

中序遍历(inorder),首先遍历左子树,然后访问根节点,最后遍历右子树(左-根-右)

后序遍历(postorder),首先遍历左子树,然后遍历右子树,最后访问根节点(左-右-根)

可见,二叉树的三种遍历方式是从根节点角度来看的,其遍历方法可以查看算法导论,如果没记错的话是采用涂色(黑、白、灰)的方法实现遍历的。

现举一例:

上图中的二叉树遍历:

先序:ABDCEFGH

中序:BDAFEHGC

后序:DBFHGECA

2)现在回归到问题本身,给出先序序列和中序序列,要复原二叉树,为了分析方便我们仍以上图中树形为例:

         12345678

先序 ABDCEFGH

中序 BDAFEHGC

根据先序序列,可以知道A为整棵树的根(先序序列第一个节点为整棵树的根),由此可以通过对中序序列进行扫描得到:

左子树的中序:BD

右子树的中序:FEHGC

另外一点我们知道,先序序列与中序序列的长度肯定是相同的,那么由此,我们又可以得到

左子树的先序:BD

右子树的先序:CEFGH

这样我们将一个大的问题划分为两个小问题,即要想复原一棵树,只需复原其根的左子树和右子树即可,由此可以采用递归的方法(其实树的问题大多都可以使用递归)

3)确定的递归方法之后,要找出递归出口,经过分析,这个问题的递归出口很简单:

a.先序(中序)序列中只有一个元素时,那么树种只有一个节点,直接返回

b.先序(中序)序列中没有元素的,空树,返回NULL。

由此得出以下代码:

//  Definition for binary tree
  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) {
		vector<int>::iterator iter;
		//递归出口
		if (preorder.empty())
		{
			return NULL;
		}
		if (preorder.size()==1)
		{
			  TreeNode * root=new TreeNode(preorder[0]);
			  return root;
		}

		//根据先序序列构造整棵树的根节点
        TreeNode * root=new TreeNode(preorder[0]);

		//获取根节点在中序序列中的位置,同时分解中序序列为“左子树”和“右子树”
		int pos=0;
		vector <int> leftInorder;
		vector <int> rightInorder;
		for (iter=inorder.begin();iter<inorder.end();iter++)
		{
			if (*iter==root->val)
			{
				break;
			}
			leftInorder.push_back(*iter);
			pos++;
		}
		pos++;
		for (iter=inorder.begin()+pos;iter<inorder.end();iter++)
		{
			rightInorder.push_back(*iter);
		}
		
		//递归求解
		vector <int> leftPreorder;
		vector <int> rightPreorder;
		for (iter=preorder.begin()+1;iter<preorder.begin()+pos;iter++)
		{
			leftPreorder.push_back(*iter);
		}
		for (;iter<preorder.end();iter++)
		{
			rightPreorder.push_back(*iter);
		}

		root->left=buildTree(leftPreorder,leftInorder);
		root->right=buildTree(rightPreorder,rightInorder);
		return root;
    }
};

提交,发现Memory Limited Exceeded!原因就在于递归中申请了太多空间,其实经过仔细分析,题目中给出的函数入口格式并不好,因为我们没有必要为先序和中序序列申请新的空间(算法中并不改变序列本身),为此自定义一个函数格式,代码如下
//  Definition for binary tree
  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) {
		//vector<int>::iterator iter;
		递归出口
		//if (preorder.empty())
		//{
		//	return NULL;
		//}
		//if (preorder.size()==1)
		//{
		//	  TreeNode * root=new TreeNode(preorder[0]);
		//	  return root;
		//}

		根据先序序列构造整棵树的根节点
  //      TreeNode * root=new TreeNode(preorder[0]);

		获取根节点在中序序列中的位置,同时分解中序序列为“左子树”和“右子树”
		//int pos=0;
		//vector <int> leftInorder;
		//vector <int> rightInorder;
		//for (iter=inorder.begin();iter<inorder.end();iter++)
		//{
		//	if (*iter==root->val)
		//	{
		//		break;
		//	}
		//	leftInorder.push_back(*iter);
		//	pos++;
		//}
		//pos++;
		//for (iter=inorder.begin()+pos;iter<inorder.end();iter++)
		//{
		//	rightInorder.push_back(*iter);
		//}
		//
		递归求解
		//vector <int> leftPreorder;
		//vector <int> rightPreorder;
		//for (iter=preorder.begin()+1;iter<preorder.begin()+pos;iter++)
		//{
		//	leftPreorder.push_back(*iter);
		//}
		//for (;iter<preorder.end();iter++)
		//{
		//	rightPreorder.push_back(*iter);
		//}

		//root->left=buildTree(leftPreorder,leftInorder);
		//root->right=buildTree(rightPreorder,rightInorder);
		//return root;
        return build(preorder,inorder,0,0,preorder.size());
    }
    TreeNode* build(vector<int> &preorder, vector<int> &inorder,int prestart,
        int instart,int seqLen)
    {
        vector<int>::iterator iter;
       /* cout<<"========================="<<endl;
        cout<<"Prestart:"<<prestart<<endl;
        cout<<"InStart:"<<instart<<endl;
        cout<<"seqLen"<<seqLen<<endl;
        for (iter=preorder.begin()+prestart;iter<preorder.begin()+prestart+seqLen;iter++)
        {
        cout<<*iter<<" ";
        }
        cout<<endl;*/
	/*	for (iter=inorder.begin()+instart;iter<inorder.begin()+instart+seqLen;iter++)
		{
			cout<<*iter<<" ";
		}
		cout<<endl;*/
		//递归出口
		if (seqLen==0)
		{
			return NULL;
		}
		if (seqLen==1)
		{
			  TreeNode * root=new TreeNode(preorder[prestart]);
			  return root;
		}

		//根据先序序列构造整棵树的根节点
        TreeNode * root=new TreeNode(preorder[prestart]);

		//获取根节点在中序序列中的位置,同时分解中序序列为“左子树”和“右子树”的起点和长度
		int leftLen=0;//左子树长度
		int rightLen=0;//右子树长度
		for (iter=(inorder.begin()+instart);iter<(inorder.begin()+instart+seqLen);iter++)
		{
			if (*iter==root->val)
			{
				break;
			}
			leftLen++;
		}
		/*leftLen++;*/
		for (iter=(inorder.begin()+instart+leftLen+1);iter<(inorder.begin()+instart+seqLen);iter++)
		{
			rightLen++;
		}
	
		root->left=build(preorder,inorder,prestart+1,instart,leftLen);
		root->right=build(preorder,inorder,(prestart+leftLen+1),(instart+leftLen+1),rightLen);
		return root;

    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值