• [LeetCode系列] 从中序遍历和后序遍历序列构造二叉树(迭代解法)


    给定中序遍历inorder和后序遍历postorder, 请构造出二叉树.

    算法思路: 设后序遍历为po, 中序遍历为io.

    • 首先取出po的最后一个节点作为根节点, 同时将这个节点入stn栈;
    • 随后比较io的最后一个节点和stn栈顶节点:
      • 如果不同则将此节点添加到栈顶节点的右侧并入stn栈, 同时从po中删除这个节点;
        • 此时的栈中保存了所有还未处理左子树的右侧根节点
        • 出现一次不同, 右侧子树的深度就增加1, 栈的深度就代表了当前右侧子树的深度
      • 如果相同, 先缓存栈顶节点, 分别删除io和栈顶元素:
        • 如果依旧相同(说明本层没有左子树), 则返回第2步;
        • 如果不同(说明有左子树), 则将po的最后一个节点添加到缓存节点p的左侧, 同时将左子树入栈并从po中删除此节点, 返回第2步;

    代码:

     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 class Solution {
    11 public:
    12     TreeNode *buildTree(vector<int> &inorder, vector<int> &postorder) {
    13         if(inorder.size() == 0)return NULL;
    14         TreeNode *p;
    15         TreeNode *root;
    16         stack<TreeNode *> stn;
    17         
    18         root = new TreeNode(postorder.back()); 
    19         stn.push(root); 
    20         postorder.pop_back(); 
    21         
    22         while(true)
    23         {
    24             if(inorder.back() == stn.top()->val) 
    25             {
    26                 p = stn.top();
    27                 stn.pop(); 
    28                 inorder.pop_back(); 
    29                 if(inorder.size() == 0) break;
    30                 if(stn.size() && inorder.back() == stn.top()->val)
    31                     continue;
    32                 p->left = new TreeNode(postorder.back()); 
    33                 postorder.pop_back();
    34                 stn.push(p->left);
    35             }
    36             else 
    37             {
    38                 p = new TreeNode(postorder.back());
    39                 postorder.pop_back();
    40                 stn.top()->right = p; 
    41                 stn.push(p); 
    42             }
    43         }
    44         return root;
    45     }
    46 };

    中序遍历的结果其实就是二叉树在垂直方向的投影.

    注意到中序遍历的最后一个元素正好是二叉树的最右端的叶子, 而后序遍历最后才访问根节点, 也即右侧根节点都按由远到近的顺序排在最后, 所以程序第一次进入if的分支时, 树的右侧所有根节点已经构造完毕并入栈, 栈顶是最右侧的根节点.

    并且此时中序遍历的结果并未删改, 我们从下到上进行左子叶的添加:

    • 如果中序遍历最后一个节点和栈上节点相同, 说明中序遍历的这个节点是根节点/右侧节点, 我们跳过它并从中序遍历和栈中删除它;
    • 但如果中序遍历的最后一个节点不是栈上节点, 这就说明此节点是当前父节点的左子叶, 我们添加它并删除它.
  • 相关阅读:
    bzoj 2599
    bzoj 3697
    poj 1741
    bzoj 2741
    bzoj 5495
    bzoj 3261
    网络流24题——骑士共存问题 luogu 3355
    网络流24题——数字梯形问题 luogu 4013
    bzoj 3998
    网络流24题——魔术球问题 luogu 2765
  • 原文地址:https://www.cnblogs.com/lancelod/p/4073739.html
Copyright © 2020-2023  润新知