【算法与数据结构】106、LeetCode从中序与后序遍历序列构造二叉树

文章目录

所有的LeetCode题解索引,可以看这篇文章------【算法和数据结构】LeetCode题解

一、题目

二、解法

思路分析:首先我们要知道后序遍历数组的最后一个元素必然是根节点,然后根据根节点在中序遍历数组中的位置进行划分,得到根节点的左右子树遍历数组,以此递归。当然这里有一个前提,遍历数组的元素不得重复,否则构造的二叉树不唯一。因此我们根据根节点的值找到中序遍历数组中的根节点索引,以此划分出左右区间,然后进行递归。

程序如下:

cpp 复制代码
class Solution {
public:
    TreeNode* traversal(const vector<int>& inorder, int inorderBegin, int inorderEnd, const vector<int>& postorder, int postorderBegin, int postorderEnd) { 
        // 1、判断是否为空数组,直接返回
        if (inorderBegin == inorderEnd || postorderBegin == postorderEnd) return NULL;

        // 2、后序遍历数组最后一个元素,就是当前的中间节点
        int rootValue = postorder[postorderEnd - 1];    
        TreeNode* root = new TreeNode(rootValue);

        // 3、叶子节点,后序数组只剩下一个元素,树构造完毕,返回
        if (postorderBegin - postorderEnd == 1) return root;

        // 4、找切割点
        int delimiterIndex;
        for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
            if (inorder[delimiterIndex] == rootValue) break; // 这里注意二叉树遍历数组的值不能重复,否则二叉树不唯一,这里默认是唯一二叉树,值不重复。
        }

        // 5、切割中序数组,得到 中序左数组和中序右数组
        int leftinorderBegin = inorderBegin;
        int leftinorderEnd = delimiterIndex;

        int rightinorderBegin = delimiterIndex + 1;
        int rightinorderEnd = inorder.size();
       
        // 6、切割后序数组,得到 后序左数组和后序右数组
        int leftpostorderBegin = postorderBegin;
        int leftpostorderEnd = postorderBegin + delimiterIndex - inorderBegin;

        // 右后序区间,左闭右开[rightPostorderBegin, rightPostorderEnd)
        int rightPostorderBegin = postorderBegin + (delimiterIndex - inorderBegin);
        int rightPostorderEnd = postorderEnd - 1; // 排除最后一个元素,已经作为节点了

        // 7、递归
        root->left = traversal(inorder, leftinorderBegin, leftinorderEnd, postorder, leftpostorderBegin, leftpostorderEnd);
        root->right = traversal(inorder, rightinorderBegin, rightinorderEnd, postorder, rightPostorderBegin, rightPostorderEnd);
        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {       
        return traversal(inorder, 0, inorder.size(), postorder, 0, postorder.size());
    }
};

三、完整代码

cpp 复制代码
# include <iostream>
# include <vector>
# include <queue>
# include <string>
# include <algorithm>
# include <stack>
using namespace std;

// 树节点定义
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(const vector<int>& inorder, int inorderBegin, int inorderEnd, const vector<int>& postorder, int postorderBegin, int postorderEnd) { 
        // 1、判断是否为空数组,直接返回
        if (inorderBegin == inorderEnd || postorderBegin == postorderEnd) return NULL;

        // 2、后序遍历数组最后一个元素,就是当前的中间节点
        int rootValue = postorder[postorderEnd - 1];    
        TreeNode* root = new TreeNode(rootValue);

        // 3、叶子节点,后序数组只剩下一个元素,树构造完毕,返回
        if (postorderBegin - postorderEnd == 1) return root;

        // 4、找切割点
        int delimiterIndex;
        for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
            if (inorder[delimiterIndex] == rootValue) break; // 这里注意二叉树遍历数组的值不能重复,否则二叉树不唯一,这里默认是唯一二叉树,值不重复。
        }

        // 5、切割中序数组,得到 中序左数组和中序右数组
        int leftinorderBegin = inorderBegin;
        int leftinorderEnd = delimiterIndex;

        int rightinorderBegin = delimiterIndex + 1;
        int rightinorderEnd = inorder.size();
       
        // 6、切割后序数组,得到 后序左数组和后序右数组
        int leftpostorderBegin = postorderBegin;
        int leftpostorderEnd = postorderBegin + delimiterIndex - inorderBegin;

        // 右后序区间,左闭右开[rightPostorderBegin, rightPostorderEnd)
        int rightPostorderBegin = postorderBegin + (delimiterIndex - inorderBegin);
        int rightPostorderEnd = postorderEnd - 1; // 排除最后一个元素,已经作为节点了

        // 7、递归
        root->left = traversal(inorder, leftinorderBegin, leftinorderEnd, postorder, leftpostorderBegin, leftpostorderEnd);
        root->right = traversal(inorder, rightinorderBegin, rightinorderEnd, postorder, rightPostorderBegin, rightPostorderEnd);
        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {       
        return traversal(inorder, 0, inorder.size(), postorder, 0, postorder.size());
    }
};

template<class T1, class T2>
void my_print2(T1& v, const string str) {
    cout << str << endl;
    for (class T1::iterator vit = v.begin(); vit < v.end(); ++vit) {
        for (class T2::iterator it = (*vit).begin(); it < (*vit).end(); ++it) {
            cout << *it << ' ';
        }
        cout << endl;
    }
}

// 层序遍历
vector<vector<int>> levelOrder(TreeNode* root) {
    queue<TreeNode*> que;
    if (root != NULL) que.push(root);
    vector<vector<int>> result;
    while (!que.empty()) {
        int size = que.size();  // size必须固定, que.size()是不断变化的
        vector<int> vec;
        for (int i = 0; i < size; ++i) {
            TreeNode* node = que.front();
            que.pop();
            vec.push_back(node->val);
            if (node->left) que.push(node->left);
            if (node->right) que.push(node->right);
        }
        result.push_back(vec);
    }
    return result;
}

int main()
{
    //vector<int> inorder = {9, 3, 15, 20, 7};
    //vector<int> postorder = { 9, 15, 7, 20, 3 };
    vector<int> inorder = { 1, 2, 3};
    vector<int> postorder = { 3, 2, 1};
    
    Solution s;
    TreeNode* root = s.buildTree(inorder, postorder);

    vector<vector<int>> tree = levelOrder(root);
    my_print2<vector<vector<int>>, vector<int>>(tree, "目标树:");

    system("pause");
    return 0;
}

end

相关推荐
AI莫大猫4 分钟前
(6)YOLOv4算法基本原理以及和YOLOv3 的差异
算法·yolo
taoyong0016 分钟前
代码随想录算法训练营第十一天-239.滑动窗口最大值
c++·算法
Uu_05kkq15 分钟前
【C语言1】C语言常见概念(总结复习篇)——库函数、ASCII码、转义字符
c语言·数据结构·算法
清梦20202 小时前
经典问题---跳跃游戏II(贪心算法)
算法·游戏·贪心算法
Dream_Snowar2 小时前
速通Python 第四节——函数
开发语言·python·算法
Altair澳汰尔2 小时前
数据分析和AI丨知识图谱,AI革命中数据集成和模型构建的关键推动者
人工智能·算法·机器学习·数据分析·知识图谱
A懿轩A3 小时前
C/C++ 数据结构与算法【栈和队列】 栈+队列详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·栈和队列
Python机器学习AI3 小时前
分类模型的预测概率解读:3D概率分布可视化的直观呈现
算法·机器学习·分类
吕小明么3 小时前
OpenAI o3 “震撼” 发布后回归技术本身的审视与进一步思考
人工智能·深度学习·算法·aigc·agi
1 9 J4 小时前
数据结构 C/C++(实验五:图)
c语言·数据结构·c++·学习·算法