【二叉树】重建二叉树

leetcode105

通过二叉树的先序和中序,或者中和后序遍历可以重建这棵二叉树。(已经先序和后序遍历并不能重构唯一的二叉树)

由先序遍历可以找出二叉树的根节点的值,再去中序/后序遍历中将节点分为左子树和右子树的节点。

一般地,有迭代和递归两种方法去重建一棵二叉树。递归比较耗时,而且确定边界时容易出错,以下代码采用迭代,时间复杂度O(n),n为树节点数。

参照先序遍历的迭代的思想,总是把左子树的左节点优先push入栈。
当栈顶元素s.top() == inorder[0]时,则说明已到达树的最左的叶子节点,随后按照先序遍历迭代思想,转向右子树。
这里设置了一个flag标志位,flag = 1转向右子树,默认flag=0持续将左子树左节点入栈。

 1 /**
 2  * Definition for binary tree
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 //用迭代的方法替换递归
11 class Solution {
12 public:
13     struct TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> in) {
14         if (pre.size() == 0 || in.size() == 0)
15             return NULL;
16         stack<TreeNode *> s;
17         int i = 0; //pre的index
18         int j = 0; //in的index
19         int flag = 0; //flag = 1转向右子树
20         TreeNode *root = new TreeNode(pre[i]);
21         TreeNode *temp = root;
22         s.push(temp);
23         i++; //push一个,则i++
24         while (i < pre.size()){
25             if (!s.empty() && s.top()->val == in[j]){
26                 temp = s.top();
27                 s.pop();
28                 flag = 1;
29                 j++;
30             }else{
31                 if (flag == 0){
32                     temp->left = new TreeNode(pre[i]);
33                     temp = temp->left;
34                     s.push(temp);
35                     i++;
36                 }else{
37                     flag = 0;
38                     temp->right = new TreeNode(pre[i]);
39                     temp = temp->right;
40                     s.push(temp);
41                     i++;
42                 }
43             }
44         }
45        return root;
46     }
47 };

下面是已经中序和后序遍历,重构二叉树。

leetcode Construct Binary Tree from Inorder and Postorder

非递归思路来自于https://leetcode.com/discuss/15115/my-comprehension-of-o-n-solution-from-%40hongzhi

首先明白,后序遍历的最后一个节点的值是二叉树的根节点的值;后序遍历是左——右——根。

从后往前遍历后序和中序的节点,如果栈顶节点的值等于中序遍历尾节点,则持续将其从中序中pop_back()以及栈中pop出来,因为前面后序中已经遍历过;如果不是,则继续从后往前遍历后序节点,作为栈顶的右孩子,同时入栈。

//已知中序和后序遍历重构二叉树
#include <iostream>
#include <vector>
#include <stack>

using namespace std;

struct TreeNode{
    int val;
    TreeNode *left, *right;
    TreeNode(int x): val(x), left(NULL), right(NULL){}
};

TreeNode *constructBinaryTree(vector<int> inorder, vector<int> postorder){
    if (inorder.size() == 0 || postorder.size() == 0){
        return NULL;
    }
    TreeNode *root = new TreeNode(postorder.back());
    postorder.pop_back();
    stack<TreeNode *> s;
    s.push(root);
    TreeNode *temp;
    while (1){
        if (inorder.back() == s.top()->val){
            temp = s.top(); //中序与后序相同的元素,保留最后一个根节点
            s.pop();
            inorder.pop_back();
            if (inorder.size() == 0) break; //pop完后检查inorder.size()
            if (!s.empty() && inorder.back() == s.top()->val) continue; //退出本次循环,下面语句不会执行
            temp->left = new TreeNode(postorder.back());
            postorder.pop_back();
            s.push(temp->left);
        } else{
            temp = new TreeNode(postorder.back());
            postorder.pop_back();
            s.top()->right = temp;
            s.push(temp);
        }
    }
    return root;
}

int main(){
    vector<int> inorder{4, 2, 5, 1, 3, 6};
    vector<int> postorder{4, 5, 2, 6, 3, 1};
    TreeNode *root = constructBinaryTree(inorder, postorder);
    cout << root->left->val << " " << root->right->val;
    return 0;
}
原文地址:https://www.cnblogs.com/cnblogsnearby/p/4737599.html