leetcode 105. 从前序与中序遍历序列构造二叉树
问题描述
根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
代码
/**
* 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 fun(0,preorder.size()-1,0,inorder.size()-1,preorder,inorder);
}
TreeNode* fun(int leftpre,int rightpre,int leftin,int rightin,vector<int>& preorder,vector<int>& inorder)
{
if(leftpre > rightpre)return NULL;
TreeNode* node = new TreeNode(preorder[leftpre]);
int i;
for(i = leftin;i <= rightin; ++i)
{
if(preorder[leftpre] == inorder[i])
break;
}
int k = i-leftin;
node->left = fun(leftpre+1,leftpre+k,leftin,i-1,preorder,inorder);
node->right = fun(leftpre+1+k,rightpre,i+1,rightin,preorder,inorder);
return node;
}
};
结果
执行用时 :52 ms, 在所有 C++ 提交中击败了31.30%的用户
内存消耗 :17.3 MB, 在所有 C++ 提交中击败了45.45%的用户
代码2
使用unordered_map代替手工查找提高效率:
/**
* 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) {
unordered_map<int,int> table;
for(int i = 0;i < inorder.size(); ++i)
table[inorder[i]] = i;
return fun(0,preorder.size()-1,0,inorder.size()-1,preorder,inorder,table);
}
TreeNode* fun(int leftpre,int rightpre,int leftin,int rightin,vector<int>& preorder,vector<int>& inorder,unordered_map<int,int>& table)
{
if(leftpre > rightpre)return NULL;
TreeNode* node = new TreeNode(preorder[leftpre]);
auto it = table.find(preorder[leftpre]);
int i = it->second;
int k = i-leftin;
node->left = fun(leftpre+1,leftpre+k,leftin,i-1,preorder,inorder,table);
node->right = fun(leftpre+1+k,rightpre,i+1,rightin,preorder,inorder,table);
return node;
}
};
结果
执行用时 :20 ms, 在所有 C++ 提交中击败了89.07%的用户
内存消耗 :17.7 MB, 在所有 C++ 提交中击败了42.42%的用户
代码3(循环实现)
如preorder[7,1,2,3,4,5,…]和inorder[7,5,…,4,…,]可知1的左子节点是2,2的左子节点是3,……,4的左子节点是5。inorder中5和4之间的节点为5的右子树。
因此有如下操作。
/**
* 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) {
if(preorder.size()==0)return NULL;
stack<TreeNode*> st;
TreeNode* ans = new TreeNode(preorder[0]);
TreeNode* tmp = NULL;
st.push(ans);
int curinorder = 0;
for(int i = 1; i < preorder.size(); ++i)
{
// 如果栈顶元素与中序的当前节点(curorder)不同,则意味着前序的当前节点(i)是栈顶结点的左儿子
if(st.top()->val != inorder[curinorder])
{
st.top()->left = new TreeNode(preorder[i]);
st.push(st.top()->left);
continue;
}
// 如果相同,则意味着前序的当前节点(i)是栈中某个元素的右儿子
while(!st.empty() && st.top()->val == inorder[curinorder])
{
tmp = st.top();
st.pop();
++curinorder;
}
tmp->right = new TreeNode(preorder[i]);
st.push(tmp->right);
}
return ans;
}
};
结果
执行用时 :8 ms, 在所有 C++ 提交中击败了99.80%的用户
内存消耗 :17 MB, 在所有 C++ 提交中击败了48.48%的用户