HTMLCOPY 由中序和后序来构造二叉树-网络避难所
隐藏
HTMLCOPY
Single

由中序和后序来构造二叉树

力扣题目:

106.从中序与后序遍历序列构造二叉树

给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。

输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
输出:[3,9,20,null,null,15,7]

思路:

找到根节点:

后序遍历数组的最后一个元素是树的根节点。这里 postorder 的最后一个元素是 3,所以根节点是 3。

匹配和切割:

在中序遍历数组中找到根节点 3 的位置。inorder 数组中,3 的位置是第 1 个。
以 3 为界将 inorder 数组分割为左子树和右子树部分:

左子树部分为 [9]。
右子树部分为 [15, 20, 7]。

根据左子树和右子树的大小分割 postorder 数组:

左子树部分为 [9],大小为 1。
右子树部分为 [15, 7, 20],大小为 3。

迭代过程:

使用一个栈来帮助构建二叉树。将根节点 3 压入栈中。
遍历 postorder 数组的元素,从倒数第二个元素开始。
根据 postorder 和 inorder 的索引关系确定节点的左右子树。

以inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]为例:

初始化:

postorder = [9, 15, 7, 20] (移除了根节点 3)
创建根节点 TreeNode(3),并将其压入栈中。
栈状态:[3]

处理右子树:

处理 postorder 的倒数第二个元素 20。
20 在 inorder 数组中的位置是 3,它在根节点 3 的右边,因此是右子树。
创建右子节点 TreeNode(20),并将其压入栈中。
栈状态:[3, 20]
postorder = [9, 15, 7]

继续处理右子树:

处理 postorder 的倒数第三个元素 7。
7 在 inorder 数组中的位置是 4,它在 20 的右边,因此是右子树。
创建右子节点 TreeNode(7),并将其压入栈中。
栈状态:[3, 20, 7]
postorder = [9, 15]

处理右子树的左子树:

处理 postorder 的倒数第四个元素 15。
15 在 inorder 数组中的位置是 2,它在 20 的左边,因此是左子树。
弹出栈顶节点直到找到合适的父节点。
创建左子节点 TreeNode(15),并将其压入栈中。
栈状态:[3, 20, 15]
postorder = [9]

处理左子树:

处理 postorder 的倒数第五个元素 9。

9 在 inorder 数组中的位置是 0,它在 3 的左边,因此是左子树。
弹出栈顶节点直到找到合适的父节点。
创建左子节点 TreeNode(9),并将其压入栈中。
栈状态:[3, 9]
postorder = [](后序遍历数组已经处理完)
通过上述过程,我们构建出了完整的二叉树。

完整代码如下:

/**
 * 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* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if (inorder.empty() || postorder.empty()) return nullptr;

        // 创建一个哈希表,存储中序遍历中每个值的索引
        unordered_map<int, int> inorderIndexMap;
        for (int i = 0; i < inorder.size(); ++i) {
            inorderIndexMap[inorder[i]] = i;
        }

        // 初始化根节点
        int postIndex = postorder.size() - 1;
        TreeNode* root = new TreeNode(postorder[postIndex--]);

        // 使用栈来辅助构建二叉树
        stack<TreeNode*> st;
        st.push(root);

        while (postIndex >= 0) {
            TreeNode* node = st.top(); // 获取栈顶节点
            int inIndex = inorderIndexMap[node->val]; // 获取当前节点在中序遍历中的索引

            // 如果当前节点在中序遍历中的索引小于后续节点,则后续节点是右子节点
            if (inIndex < inorderIndexMap[postorder[postIndex]]) {
                node->right = new TreeNode(postorder[postIndex--]); // 创建右子节点
                st.push(node->right); // 右子节点入栈
            } else {
                // 否则,处理左子树
                while (!st.empty() && inorderIndexMap[st.top()->val] > inorderIndexMap[postorder[postIndex]]) {
                    node = st.top();
                    st.pop(); // 弹出栈顶节点,继续寻找父节点
                }
                node->left = new TreeNode(postorder[postIndex--]); // 创建左子节点
                st.push(node->left); // 左子节点入栈
            }
        }

        return root; // 返回构建的二叉树根节点

    }
};

按照这个思路,可以做另一道类似的题:

105.从前序与中序遍历序列构造二叉树

题目代码如下:

/**
 * 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* buildTree(vector<int>& preorder, vector<int>& inorder) {
        // 创建一个哈希表存储每个值在中序遍历中的索引
        unordered_map<int, int> inorderIndexMap;
        for (int i = 0; i < inorder.size(); i++) {
            inorderIndexMap[inorder[i]] = i;
        }

        // 用于跟踪前序遍历的当前索引
        int preIndex = 0;
        
        // 用前序遍历的第一个值初始化根节点
        TreeNode* root = new TreeNode(preorder[preIndex++]);
        
        // 使用一个栈来帮助构建树
        stack<TreeNode*> st;
        st.push(root);
        
        // 遍历前序遍历的剩余部分
        while (preIndex < preorder.size()) {
            TreeNode* node = st.top();
            int currentPreorderVal = preorder[preIndex];
            int inIndex = inorderIndexMap[node->val];
            int currentInorderIndex = inorderIndexMap[currentPreorderVal];
            
            // 如果当前前序遍历的值在中序遍历中位于节点的左边,
            // 这意味着我们仍然在遍历左子树。
            if (currentInorderIndex < inIndex) {
                node->left = new TreeNode(currentPreorderVal);
                st.push(node->left);
            } else {
                // 否则,意味着我们需要添加一个节点到右子树。
                while (!st.empty() && inorderIndexMap[st.top()->val] < currentInorderIndex) {
                    node = st.top();
                    st.pop();
                }
                node->right = new TreeNode(currentPreorderVal);
                st.push(node->right);
            }
            preIndex++;
        }
        
        return root;
    }
};

 

 

暂无评论

发表评论

HTMLCOPY