Construct Binary Tree from Preorder and Inorder Traversal
题目连接:https://oj.leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
runtimes:55ms
一、问题
Given preorder and inorder traversal of a tree, construct the binary tree.
已经完成类似的题目:http://blog.csdn.net/shawjan/article/details/42464289
二、分析
吸取了之前一道题最好解法的精髓,将一个大问题分解成为若干个小问题,在解决若干个小问题。
例如:前序排列 A B D E G C F 中序排列 D B G E A C F。首先我们需要解决这个大问题,A作为树的根,那么接下来就需要解决A的左子树和右子树两个子问题,而左子树对应的前序排列 B D E G, 中序排列 D B G E,右子树对应的前序排列 C F,中序排列 C F。依次类推,我们需要解决以B为根的左子树和右子树两个小问题和以C为根的左子树和右子树的小问题。如果序列为空,则说明该小问题所在的根为空。
三、小结
采取了递归和非递归两种方案,显然递归方案运行内存超出限制,因此改为非递归方案,但也跑了84ms之多,让我这个追求速度的汉子情何以堪。
四、方案
递归方案的实现:
class Solution {
public:
TreeNode *buildTree2(vector<int> pre, vector<int> in, int s1, int e1, int s2, int e2)
{
if (s2 > e2 || s1 > e1)
return NULL;
int i;
for (i = s2; i <= e2; i++)
{
if (pre[s1] == in[i])
break;
}
struct TreeNode *tree = new TreeNode(pre[s1]);
tree->left = buildTree2(pre, in, s1 + 1, i - s2 + s1, s2, i - 1);
tree->right = buildTree2(pre, in, e1 - e2 + i + 1, e1, i + 1, e2);
return tree;
}
void outPut(TreeNode *tree)
{
if (tree == NULL)
return;
cout << tree->val << " ";
outPut(tree->left);
outPut(tree->right);
}
TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder) {
if (preorder.size() == 0 || inorder.size() == 0)
return NULL;
TreeNode *tree = buildTree2(preorder, inorder, 0, preorder.size() - 1, 0, inorder.size() - 1);
outPut(tree);
return tree;
}
};
非递归方案的实现:
class Solution {
public:
TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder) {
if (preorder.size() == 0 || inorder.size() == 0)
return NULL;
TreeNode *tree = new TreeNode(preorder[0]);
vector <TreeNode *> treeVec;
vector <int> paraVec;
treeVec.push_back(tree);
paraVec.push_back(0); paraVec.push_back(preorder.size() - 1);
paraVec.push_back(0); paraVec.push_back(inorder.size() - 1);
while (paraVec.size() > 0)
{
int s1, e1, s2, e2;
e2 = paraVec.back(); paraVec.pop_back();
s2 = paraVec.back(); paraVec.pop_back();
e1 = paraVec.back(); paraVec.pop_back();
s1 = paraVec.back(); paraVec.pop_back();
int i;
for (i = s2; i <= e2; i++) //改了这里发现可以减少29ms,真是惊呆了,原来是for(<span style="font-family: Arial, Helvetica, sans-serif;">i = 0; i < inorder.size(); i++</span>)
{
if (preorder[s1] == inorder[i])
break;
}
TreeNode *tree2 = treeVec.back(); treeVec.pop_back();
tree2->val = preorder[s1];
if (s1 + 1 <= i - s2 + s1 && s2 <= i - 1)
{
paraVec.push_back(s1 + 1); paraVec.push_back(i - s2 + s1);
paraVec.push_back(s2); paraVec.push_back(i - 1);
TreeNode *treeLeft = new TreeNode(0);
tree2->left = treeLeft;
treeVec.push_back(treeLeft);
}
if (e1 - e2 + i + 1 <= e1 && i + 1 <= e2)
{
paraVec.push_back(e1 - e2 + i + 1); paraVec.push_back(e1);
paraVec.push_back(i + 1); paraVec.push_back(e2);
TreeNode *TreeRight = new TreeNode(0);
tree2->right = TreeRight;
treeVec.push_back(TreeRight);
}
}
return tree;
}
};
五、三思
叼!找了很久找到了一个24ms的程序,哇, 吓尿了。get到了两个新技能,一个是auto的使用,在c++98中有,用来自动判断声明变量的类型,但是极少用而且多余,后来被c++11删除了;其次是unordered_map和map的使用,酱紫会大大降低了运行时间,小伙伴都惊呆了,原来库函数的威力如此之大,以后要专研一下库函数才是。思想和我如出一则,不再赘述。
原文链接:http://blog.xiaohuahua.org/2014/12/17/leetcode-construct-binary-tree-from-preorder-and-inorder-traversal/