# Definition for a binary tree node.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def constructFromPrePost(self, preorder, postorder):
if not preorder:
return None
root = TreeNode(preorder[0])
if len(preorder) == 1:
return root
# Find the left subtree root in postorder
left_root_val = preorder[1]
left_subtree_size = postorder.index(left_root_val) + 1
root.left = self.constructFromPrePost(preorder[1:left_subtree_size+1], postorder[:left_subtree_size])
root.right = self.constructFromPrePost(preorder[left_subtree_size+1:], postorder[left_subtree_size:-1])
return root
/**
* 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:
TreeNode* constructFromPrePost(vector& preorder, vector& postorder) {
if (preorder.empty()) return nullptr;
TreeNode* root = new TreeNode(preorder[0]);
if (preorder.size() == 1) return root;
int left_root_val = preorder[1];
int left_subtree_size = 0;
for (int i = 0; i < postorder.size(); ++i) {
if (postorder[i] == left_root_val) {
left_subtree_size = i + 1;
break;
}
}
root->left = constructFromPrePost(
vector(preorder.begin() + 1, preorder.begin() + 1 + left_subtree_size),
vector(postorder.begin(), postorder.begin() + left_subtree_size)
);
root->right = constructFromPrePost(
vector(preorder.begin() + 1 + left_subtree_size, preorder.end()),
vector(postorder.begin() + left_subtree_size, postorder.end() - 1)
);
return root;
}
};
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode constructFromPrePost(int[] preorder, int[] postorder) {
return build(preorder, 0, preorder.length - 1, postorder, 0, postorder.length - 1);
}
private TreeNode build(int[] preorder, int preStart, int preEnd, int[] postorder, int postStart, int postEnd) {
if (preStart > preEnd) return null;
TreeNode root = new TreeNode(preorder[preStart]);
if (preStart == preEnd) return root;
int leftRootVal = preorder[preStart + 1];
int leftIndex = postStart;
while (postorder[leftIndex] != leftRootVal) leftIndex++;
int leftSize = leftIndex - postStart + 1;
root.left = build(preorder, preStart + 1, preStart + leftSize, postorder, postStart, leftIndex);
root.right = build(preorder, preStart + leftSize + 1, preEnd, postorder, leftIndex + 1, postEnd - 1);
return root;
}
}
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {number[]} preorder
* @param {number[]} postorder
* @return {TreeNode}
*/
var constructFromPrePost = function(preorder, postorder) {
if (preorder.length === 0) return null;
const root = new TreeNode(preorder[0]);
if (preorder.length === 1) return root;
const leftRootVal = preorder[1];
const leftSubtreeSize = postorder.indexOf(leftRootVal) + 1;
root.left = constructFromPrePost(preorder.slice(1, leftSubtreeSize + 1), postorder.slice(0, leftSubtreeSize));
root.right = constructFromPrePost(preorder.slice(leftSubtreeSize + 1), postorder.slice(leftSubtreeSize, postorder.length - 1));
return root;
};
preorder
and postorder
that represent the preorder and postorder traversal of a binary tree, construct and return the binary tree that generated these traversals.
preorder
and postorder
is unique.preorder
and inorder
(or postorder
and inorder
), since the inorder traversal gives a clear left/right subtree boundary. However, with only preorder
and postorder
, it's less obvious.
The key insight is that:
preorder
traversal visits nodes in root - left - right order.postorder
traversal visits nodes in left - right - root order.preorder
array is empty, return null
(no nodes to construct).
preorder
is always the root of the current subtree.
preorder
is the root of the left subtree. Find this value in postorder
to determine the size of the left subtree (since postorder
lists all left subtree nodes before the right subtree and root).
preorder
and postorder
.preorder = [1, 2, 4, 5, 3, 6, 7]
postorder = [4, 5, 2, 6, 7, 3, 1]
preorder
is 1 (the root).postorder
(index 2). So, the left subtree has 3 nodes (4, 5, 2
).preorder[1:4] = [2, 4, 5]
, postorder[0:3] = [4, 5, 2]
preorder[4:] = [3, 6, 7]
, postorder[3:6] = [6, 7, 3]
[4]
, [4]
(returns node 4)
[5]
, [5]
(returns node 5)
[6]
, [6]
(returns node 6)
[7]
, [7]
(returns node 7)
postorder
(which is O(n) per node in the naive implementation). With further optimization (using a hash map to store value-to-index mappings), we can reduce this to O(1) per lookup.