zlatan的算法笔记18--从中序与后序遍历序列构造二叉树(力扣106题)

算法笔记

本题是构造二叉树类的一道题,从思想的角度来看,很多人应该都应该会在纸上通过中序与另一种遍历方法来构造二叉树,解决本题需要提前弄清楚这个逻辑,这样在代码实现的时候思路会更好理清楚。

题目描述

zlatan的算法笔记18--从中序与后序遍历序列构造二叉树(力扣106题)_第1张图片

解题思路

zlatan的算法笔记18--从中序与后序遍历序列构造二叉树(力扣106题)_第2张图片这里首先附上一张无代码情况下中序与后序遍历的构造二叉树过程,我们在代码实现的时候也应该从几个步骤分别考虑:

第一步:如果两个数组大小为零的话,说明是空节点了。

第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。

第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点

第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)

第五步:切割后序数组,切成后序左数组和后序右数组

第六步:递归处理左区间和右区间

简单解释一下这个整体步骤,可以对照代码来看,我们先优先判断两个数组是否为空,如果有一个为空,那么就无法构造,直接结束即可。在后序遍历中,最后一个值永远都会是根节点,所以我们优先通过这个步骤去找到根节点,即将后序数组的最后一项赋值为根节点的值,建立根节点并将它进行赋值为rootValue。其次定义一个切割点用于分割二叉树当中的左右子树,那么这个切割点应该在哪里找呢?根据遍历的特性,应该去选择中序遍历来找到切割点,即遍历这个数组当某一项的值等于根节点的值,就可以退出循环找点分割点的索引。

紧接着就可以进一步进行切割,切割过程需要注意的问题还是区间问题,到底是选择左闭右闭还是左闭右开,搞不清楚就容易出错。这里坚持左闭右开原则。首先应该先切割中序数组,切割点在后序数组的最后一个元素,就是用这个元素来切割中序数组的,所以必要先切割中序数组。切割过程看代码就可以了,通俗易懂。然后就是切割后序数组,在切割前首先要丢掉后序数组里面的最后一项元素,那个根节点已经被用掉了,然后再切割即可,至此切割步骤就完成了。最后递归处理一下左右区间,让整个二叉树构造起来就可以了。

代码部分

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* traversal(vector<int>& inorder, vector<int>& postorder) {
        if(postorder.size() == 0) {
            return nullptr;
        }
        int rootValue = postorder[postorder.size() - 1];
        TreeNode* root = new TreeNode(rootValue);

        if(postorder.size() == 1) {
            return root;
        }

        int cutIndex = 0;
        for(cutIndex = 0; cutIndex < inorder.size(); cutIndex++) {
            if(inorder[cutIndex] == rootValue) break;
        }

        vector<int> leftInorder(inorder.begin(), inorder.begin() + cutIndex);
        vector<int> rightInorder(inorder.begin() + cutIndex + 1, inorder.end());

        postorder.resize(postorder.size() - 1);

        vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());
        vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end());

        root->left = traversal(leftInorder, leftPostorder);
        root->right = traversal(rightInorder, rightPostorder);

        return root; 
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if(inorder.size() == 0 || postorder.size() == 0) {
            return nullptr;
        }
        return traversal(inorder, postorder);
    }
};

结语

本题使用文字描述可能仍会存在很多问题,所以我个人比较建议去看《代码随想录》有关于这道题目的讲解视频,多看几遍就可以熟悉整个构造二叉树的过程,希望对大家有所帮助–视频教程。

你可能感兴趣的:(算法,leetcode,数据结构)