力扣题目:
给定两个整数数组 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; } };
暂无评论