14. 构造二叉树

📃 题目一描述

题目链接:从中序与后序遍历构造二叉树

image-20220527234841688

🔔 解题思路

必须明确条件:给出一个数组的值中,是没有重复的数字的,即没用节点的数值是相同的!

画图分析:(图来自dong哥)

img

可以很明确得知:后续遍历数组中postEnd就是中点的值,通过中点的值我们就可以在中序遍历数组中找到中点的位置,从而分割出左子树,右子树,递归就可以完成构建;

class Solution {
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        return build(inorder, 0, inorder.size() - 1, postorder, 0, postorder.size() - 1);
    }

    //都是不同的值组成,不存在“中”在左子树中出现的情况;
    TreeNode* build(vector<int>& inorder, int inStart, int inEnd, vector<int>& postorder, int postStart, int postEnd) {
        if (inStart > inEnd) return nullptr;

        int rootVal = postorder[postEnd];
        int size = 0;
        for (int i = inStart; i <= inEnd; i++) {
            if (rootVal == inorder[i]) { // 找到中序遍历“左 中 右” 的 “中”;
                size = i - inStart; // 记录左的长度,需要使用其长度求其他下标 =》 因为起点不一定是从0开始,要用相对值
                break;
            }
        }

        //构建中节点,左右子树
        TreeNode *root =  new TreeNode(rootVal);
        root->left = build(inorder, inStart, inStart + size - 1, postorder, postStart, postStart + size - 1);
        root->right = build(inorder, inStart + size + 1, inEnd, postorder, postStart + size, postEnd - 1);
        return root;
    }
};

📃 题目二描述

题目链接:从前序与中序遍历构造二叉树

image-20220527234913503

🔔 解题思路

同上,依据图来写代码即可:

img

class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        return build(preorder, 0, preorder.size() - 1, inorder, 0, inorder.size() - 1);
    }

    TreeNode* build(vector<int>& preorder, int preStart, int preEnd, vector<int>& inorder, int inStart, int inEnd) {
        if (preStart > preEnd) return nullptr;

        int rootVal = preorder[preStart];
        int size = 0;
        for (int i = inStart; i <= inEnd; i++) {
            if (inorder[i] == rootVal) {
                size = i -inStart;
                break;
            }
        }

        // 开始构建树
        TreeNode* root = new TreeNode(rootVal);
        root->left = build(preorder, preStart + 1, preStart + size, inorder, inStart, inStart + size - 1);
        root->right = build(preorder, preStart + size + 1, preEnd, inorder, inStart + size + 1, inEnd);
        return root;
    }
};

📃 题目三描述

题目链接:根据前序和后序遍历构造二叉树

image-20220528001200698

🔔 解题思路

这道题与前两道题的不同之处:通过前序和后序是无法确定唯一一颗二叉树的!

原因:看图

image-20220528001913775

前序和后序只能确定中,无法确定左右的边界!可能压根就没有左指针或者右指针 例如:preorder = [1,2,3], postorder = [3,2,1],而下图两种树结构都满足;

img

理解:我们假设前序遍历的第二个元素是左子树的根节点(左图),但实际上左子树有可能是空指针(右图),那么这个元素就应该是右子树的根节点。由于这里无法确切进行判断,所以导致了最终答案的不唯一。

这道题如何做:①确定根节点,②将前序遍历数组中根节点后的下一位为左根节点(preStart + 1, 自己也快选定其他), ③在后序遍历数组中找到该左根节点的位置,从而分割左右子树;如图:

img

代码:

class Solution {
public:
    TreeNode* constructFromPrePost(vector<int>& preorder, vector<int>& postorder) {
        return build(preorder, 0, preorder.size() - 1, postorder, 0, postorder.size() - 1);
    }
    TreeNode* build(vector<int>& preorder, int preStart, int preEnd, vector<int>& postorder, int postStart, int postEnd) {
        if (preStart > preEnd) return nullptr;

        int rootVal = preorder[preStart];
        if (preStart == preEnd) return new TreeNode(rootVal);
        int leftRootVal = preorder[preStart + 1];
        int size = 0;
        for (int i = postStart; i <= postEnd; i++) {
            if (postorder[i] == leftRootVal) {
                size = i - postStart;
                break;
            }
        }

        //构建二叉树
        TreeNode* root = new TreeNode(rootVal);
        root->left = build(preorder, preStart + 1, preStart + size + 1, postorder, postStart, postStart + size);
        root->right = build(preorder, preStart + size + 2, preEnd, postorder, postStart + size + 1, postEnd);
        return root; 
    }
};

优化建议:以上三题,均是不重复数组,可以用空间换时间的想法:可以采用哈希表记录 需要遍历的数组 对应的index, 这样在每次遍历的时候可以直接得到想要查询数的下标

📃 题目四描述(简单练手题)

题目链接:最大二叉树

image-20220528010720855

image-20220528010736088

🔔 解题思路

根据构造树的思想,依题目构造即可

class Solution {
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        return build(nums, 0, nums.size() - 1);
    }
    TreeNode* build(vector<int>& nums, int start, int end) {
        if (start > end) return nullptr;

        int rootVal = INT_MIN;
        int index = 0;
        for (int i = start; i <= end; i++) {
            if (rootVal < nums[i]) {
                index = i;
                rootVal = nums[i];
            }
        }

        //构建树
        TreeNode* root = new TreeNode(rootVal);
        root->left = build(nums, start, index - 1);
        root->right = build(nums, index + 1, end);
        return root;
    }
};
posted @ 2022-05-28 00:43  D-booker  阅读(174)  评论(0编辑  收藏  举报