剑指Offer 07 重建二叉树

参考学习题解:
剑指 Offer 07. 重建二叉树(分治算法,清晰图解)作者:Krahets

解题思路:
前序遍历性质: 节点按照 [ 根节点 | 左子树 | 右子树 ] 排序。
中序遍历性质: 节点按照 [ 左子树 | 根节点 | 右子树 ] 排序。

以题目示例为例:

前序遍历划分 [ 3 | 9 | 20 15 7 ]
中序遍历划分 [ 9 | 3 | 15 20 7 ]
根据以上性质,可得出以下推论:

  1. 前序遍历的首元素 为 树的根节点 node 的值。
  2. 在中序遍历中搜索根节点 node 的索引 ,可将 中序遍历 划分为 [ 左子树 | 根节点 | 右子树 ] 。
  3. 根据中序遍历中的左(右)子树的节点数量,可将 前序遍历 划分为 [ 根节点 | 左子树 | 右子树 ] 。

作者:jyd
链接:https://leetcode.cn/problems/zhong-jian-er-cha-shu-lcof/solution/mian-shi-ti-07-zhong-jian-er-cha-shu-di-gui-fa-qin/
来源:力扣(LeetCode)


为了提升效率,本文使用哈希表 dic 存储中序遍历的值与索引的映射,查找操作的时间复杂度为
O(1) ;

作者:laoceot

/**
 * 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:
    unordered_map<int,int> map;
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        // 将中序序列用哈希表存储,便于查找根节点
        for(int i = 0;i < inorder.size();i++)
            map[inorder[i]] = i;
        // 传入参数:前序,中序,前序序列根节点,中序序列左边界,中序序列右边界
        return build(preorder,inorder,0,0,inorder.size()-1);
    }

    TreeNode* build(vector<int>& preorder, vector<int>& inorder,int pre_root,int in_left,int in_right){
        if(in_left > in_right)
            return NULL;
        TreeNode* root = new TreeNode(preorder[pre_root]);
        // 根节点在中序序列中的位置,用于划分左右子树的边界
        int in_root = map[preorder[pre_root]];
        // 左子树在前序中的根节点位于:pre_root+1,左子树在中序中的边界:[in_left,in_root-1]
        root->left = build(preorder,inorder,pre_root+1,in_left,in_root-1);
        // 右子树在前序中的根节点位于:根节点+左子树长度+1 = pre_root+in_root-in_left+1
        // 右子树在中序中的边界:[in_root+1,in_right]
        root->right = build(preorder,inorder,pre_root+in_root-in_left+1,in_root+1,in_right);
        return root;
    }
};


####Q:右子树在前序中的根节点位于:根节点+左子树长度+1 = pre_root+in_root-in_left+1 这个是怎么算的。 左子树的长度应该是多少

A:
右子树在前序中的根节点下标 = 根节点下标 + 左子树长度 + 1

其中,根节点下标是 pre_root,左子树的长度可以在中序遍历中计算得到,即 in_root - in_left。

所以,右子树在前序遍历中的根节点下标可以计算为:

pre_root + in_root - in_left + 1

左子树的长度应该是 in_root - in_left,因为在中序遍历中,根节点左边的元素都属于左子树,右边的元素都属于右子树。所以,根据根节点在中序遍历中的下标 in_root 和左边界 in_left 的差值,即可得到左子树的长度。

posted @ 2023-03-19 15:24  专心Coding的程侠  阅读(8)  评论(0编辑  收藏  举报