首先,先序遍历先访问根节点,而中序遍历的结果是整个树的垂直投影,因此可以根据先序遍历的首节点将中序遍历划分为左右子树,然后先序遍历的第二个结点是左子树的根节点,又可以将刚刚划分的左子树进一步划分为左右子树,一直划分到中序遍历的划分区间中只剩下一个结点,则该结点是一个叶子结点。
按照这种思路:
/**
* 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) {
int preorder_ptr=0;
int inorder_start=0;
int inorder_end=preorder.size();
return buildTree(preorder,preorder_ptr, inorder,inorder_start,inorder_end);
}
private:
TreeNode* buildTree(const vector<int>& preorder,int& preorder_ptr, const vector<int>& inorder,int inorder_start,int inorder_end) {
//[inorder_start,inorder_end)
if(inorder_end==inorder_start)
return nullptr;
if(inorder_end-inorder_start==1){
preorder_ptr++;
return new TreeNode(inorder[inorder_start]);
}else {
auto ptr=find(inorder.begin(),inorder.end(),preorder[preorder_ptr++]);
TreeNode* p=new TreeNode(*ptr);
int x=ptr-inorder.begin();
p->left=buildTree(preorder,preorder_ptr, inorder,inorder_start,x);
p->right=buildTree(preorder,preorder_ptr, inorder,x+1,inorder_end);
return p;
}
}
};
其中的preorder_ptr是引用类型,保证了所有递归函数共用一个preorder_ptr,使得先序序列不停推进进行划分。完成上面的递归过程。
这种思路是先序序列不停推进,从中序序列中不断划分,以构建二叉树。
递归版本:
return create(preorder, inorder, 0, preorder.size() - 1, 0, inorder.size() - 1);
}
if(preorder_start > preorder_end){
return nullptr;
}
TreeNode* node = new TreeNode(preorder[preorder_start]);
int pos;
for(int i = inorder_start; i <= inorder_end; i++){
if(inorder[i] == preorder[preorder_start]){
pos = i;
break;
}
}
node->left = create(preorder, inorder, preorder_start + 1, preorder_start + pos - inorder_start, inorder_start, pos - 1);
node->right = create(preorder, inorder, preorder_end - inorder_end + pos + 1, preorder_end, pos + 1, inorder_end);
return node;
}
中序-后序也是一样,后序序列最后一个结点必为根结点,倒数第二个结点必为根的右孩子,然后去中序序列中划分范围递归去做。
代码如下:
public:
TreeNode* buildTree(vector<int>& inorder,vector<int>& postorder) {
int post_ptr = postorder.size() - 1;
int in_start = 0;
int in_end = postorder.size() - 1;
return buildTree_t(inorder, postorder, post_ptr, in_start, in_end);
}
private:
TreeNode* buildTree_t(const vector<int>& inorder, const vector<int>& postorder, int& post_ptr, int in_start, int in_end) {
if (in_end < in_start)
return nullptr;
if (in_end == in_start) {
TreeNode* p = new TreeNode(inorder[in_end]);
post_ptr--;
return p;
}
else {
auto ps = find(inorder.begin(), inorder.end(), postorder[post_ptr--]);
TreeNode* p = new TreeNode(*ps);
int i = ps - inorder.begin();
p->right = buildTree_t(inorder, postorder, post_ptr, i + 1, in_end);
p->left = buildTree_t(inorder, postorder, post_ptr, in_start, i - 1);
return p;
}
}
中序-先序还有一种思路:
由于先序序列第一个元素一定是根,那么先建立一个根结点,第一个元素后的第二个元素一定是根节点的左子树的根结点,那么根的左孩子结点的值也确定,每确定一个结点,将这个结点压栈,也就是每读一个先序点就建立一个结点并压栈,那么栈自顶向下的顺序就是左孩子到根的顺序,一定和中序保持一致。
如果栈顶元素和中序序列不匹配了只能说明一个问题:先序序列的根左右顺序导致往栈里面放进去了一个祖先根结点,而此时中序序列的左根右的特点导致出现了一个祖先根结点的孩子结点的右结点,那么,从先序序列中获得那个右结点并添加到该结点上。
中序序列的作用在于提示什么时候先序序列的点是栈顶元素的右结点。
代码如下:
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
public:
TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder) {
if (preorder.size() == 0)
return nullptr;
stack<int> stack_preorder_label;
stack<TreeNode *> stack_tree_node;
TreeNode *root = new TreeNode(preorder[0]);
TreeNode *current_node = root;
int preorder_ptr = 0;
int inorder_ptr = 0;
bool set_right_when_dismatch = false;
stack_preorder_label.push(preorder[0]);
stack_tree_node.push(root);
preorder_ptr++;
while (preorder_ptr < preorder.size())
{
if (!stack_tree_node.empty() && stack_tree_node.top()->val == inorder[inorder_ptr])
{
current_node = stack_tree_node.top();
stack_tree_node.pop();
stack_preorder_label.pop();
set_right_when_dismatch = true;
inorder_ptr++;
}
else
{
if (set_right_when_dismatch == false)
{
stack_preorder_label.push(preorder[preorder_ptr]);
current_node->left = new TreeNode(preorder[preorder_ptr]);
current_node = current_node->left;
stack_tree_node.push(current_node);
preorder_ptr++;
}
else
{
set_right_when_dismatch = false;
stack_preorder_label.push(preorder[preorder_ptr]);
current_node->right = new TreeNode(preorder[preorder_ptr]);
current_node = current_node->right;
stack_tree_node.push(current_node);
preorder_ptr++;
}
}
}
}
};