LeetCode Construct Binary Tree from Inorder and Postorder Traversal 思考分析过程分享

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

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

利用二叉树的中序和后序的序列还原一颗二叉树。

Note的意思是如果有节点的值是重复的话,那么就无法确保这颗二叉树是唯一的了。

一开始我基本上是毫无头绪。然后思考:

1 画图: 把二叉树和其中序和后序的序列都画出来(这个很重要,我以前有时候总是凭空想象,结果脑子一片空白)

画图也注意把特殊情况都画下来!

2 把问题写下来:怎么构造一个节点?用什么算法?能用递归吗?从什么地方开始构造?根节点?反正能想到的问题都写下来。一定要写下来!

--问题一定要考虑上特殊情况的问题,也一定要写下来。

--其中边界作为主要特殊情况,优先考虑。

3观察:到底有什么特点是可以利用来解题的呢? A)后序最后一个一定是根节点 B)中序第一个一定是最左边的根节点。C)根节点左右子树是可以分开的

观察总结:那么什么特点是有用的呢?A)C)是有用的;B)好像是无用的。

利用A)C)可以构造递归,每递归一次可以构造一个节点。

4 分治:什么问题需要什么函数解决,一定要把函数分到最小。

做起来又发现很多“小问题”:

1)每个节点必须用new动态分配内存,因为不能返回局部函数指针地址

2)利用C)特性分开左右子树很麻烦,因为要维持4个边界,这样的情况要极其小心,因为很容易下标越界等问题出来的。最好写个更小的程序,先验证过下标处理正确之后再调用该函数。(这个非常麻烦!每次需要打起12分精神)

3)递归参数如何处理?一开始我是想剪裁vector,每次把新的vector装的中序和后序数列递归传递给下一个递归函数,但是这样就会造成大量的参数传递,是个非常糟糕的做法。程序能运行也很糟糕。千万不能用vector作参数递归调用。应该是使用其下标,每次用下标标明需要vector中的哪一部分进行运算!

4)特殊情况处理,4个边界处理,空树,树为一个根节点。

感觉好辛苦,一个编程任务,如临大敌似的!不知道是不是功力不到。

突然想到这是不就像是金庸武功第一层境界:举重若重。

不知道别人是不是到了第二层境界了:举重若轻

第三层境界:举轻若重!

最后:摘叶飞花!

12-4update:再次看看觉得自己已经快要超越第一层境界了。超越了就不置顶了。

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 split(inorder, 0, inorder.size(), postorder, 0, postorder.size());
	}

	TreeNode *split(vector<int> &in, int inbeg,int inend, vector<int>& po, int pobeg, int poend)
	{
		if(in.empty()) return nullptr;
		TreeNode *node = new TreeNode(po[poend-1]);
		if(in.size() <= 1) return node;

		auto initer = find(in.begin()+inbeg, in.begin()+inend, po[poend-1]);
		int lnum = initer - in.begin() - inbeg;
		int rnum = inend - inbeg - lnum - 1;

		int linbeg = inbeg;
		int linend = inbeg + lnum;
		int rinbeg = inbeg + lnum + 1;
		int rinend = inend;

		int lpobeg = pobeg;
		int lpoend = pobeg + lnum;
		int rpobeg = pobeg + lnum;
		int rpoend = poend - 1;

		if(linbeg<linend)
			node->left = split(in, linbeg, linend, po, lpobeg, lpoend);
		if(rinbeg<rinend)
			node->right = split(in, rinbeg, rinend, po, rpobeg, rpoend);

		return node;
	}
};


测试程序:

#include<iostream>
#include<vector>

using namespace std;

void printTree(TreeNode *root)
{
	if(!root) return;
	cout<<root->val<<" ";
	printTree(root->left);
	printTree(root->right);
}


int main()
{
	TreeNode *root;
	TreeNode *re;
	int a[] = {8,4,2,5,1,6,3,7};
	int b[] = {8,4,5,2,6,7,3,1};
	vector<int> li(a, a+8);
	vector<int> ri(b, b+8);
	Solution solu;

	root = solu.buildTree(li,ri);

	printTree(root);
	cout<<endl;

	li.clear();
	ri.clear();
	re = solu.buildTree(li,ri);
	printTree(re);
	cout<<endl;

	system("pause");
	return 0;
}

最后这些方法论都已经融入思维当中,能本能地逻辑思考了。

这种题目已经是非常轻松的了,那么就算是举重若轻吧。O(∩_∩)O~

//2014-2-16 update
	TreeNode *buildTree(vector<int> &inorder, vector<int> &postorder) 
	{
		return build(inorder, 0, inorder.size()-1, postorder, 0, postorder.size()-1);
	}
	TreeNode *build(vector<int> &inorder, int in1, int in2,
		vector<int> &postorder, int po1, int po2) 
	{
		if (in1 > in2) return nullptr;
		TreeNode *root = new TreeNode(postorder[po2]);
		int offset = 0;//注意是offset,一定要多走几个例子,了解好所有情况!
		for (int i = in1; inorder[i+offset] != postorder[po2]; offset++);

		root->left = build(inorder, in1, in1+offset-1, postorder, po1, po1+offset-1);
		root->right = build(inorder, in1+offset+1, in2, postorder, po1+offset, po2-1);
		return root;//别忘记了return 答案!
	}


//2014-2-16 update 中序构造
	TreeNode *buildTree(vector<int> &inorder, vector<int> &postorder) 
	{
		return build(inorder, 0, inorder.size()-1, postorder, 0, postorder.size()-1);
	}
	TreeNode *build(vector<int> &inorder, int in1, int in2,
		vector<int> &postorder, int po1, int po2) 
	{
		if (in1 > in2) return nullptr;
		int offset = 0;//注意是offset,一定要多走几个例子,了解好所有情况!
		for (int i = in1; inorder[i+offset] != postorder[po2]; offset++);
		TreeNode *lt = build(inorder, in1, in1+offset-1, postorder, po1, po1+offset-1);
		TreeNode *root = new TreeNode(postorder[po2]);
		root->left = lt;
		root->right = build(inorder, in1+offset+1, in2, postorder, po1+offset, po2-1);
		return root;
	}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值