Given two integer arrays, preorder and postorder where preorder is the preorder traversal of a binary tree of distinct values and postorder is the postorder traversal of the same tree, reconstruct and return the binary tree.
If there exist multiple answers, you can return any of them.
It is guaranteed that preorder and postorder are the preorder traversal and postorder traversal of the same binary tree.
Solutions
Solution 1: Recursion
The order of pre-order traversal is: root node -> left subtree -> right subtree, and the order of post-order traversal is: left subtree -> right subtree -> root node.
Therefore, the root node of the binary tree must be the first node of the pre-order traversal and the last node of the post-order traversal.
Next, we need to determine the range of the left and right subtrees of the binary tree.
If the binary tree has a left subtree, then the root node of the left subtree must be the second node of the pre-order traversal; if the binary tree does not have a left subtree, then the second node of the pre-order traversal must be the root node of the right subtree. Since the results of post-order traversal in these two cases are the same, we can take the second node of the pre-order traversal as the root node of the left subtree, and then find its position in the post-order traversal, so as to determine the range of the left subtree.
Specifically, we design a recursive function $dfs(a, b, c, d)$, where $[a, b]$ represents the range of pre-order traversal, and $[c, d]$ represents the range of post-order traversal. The function of this function is to construct the root node of the binary tree based on the pre-order traversal $[a, b]$ and the post-order traversal $[c, d]$. The answer is $dfs(0, n - 1, 0, n - 1)$, where $n$ is the length of the pre-order traversal.
The execution steps of the function $dfs(a, b, c, d)$ are as follows:
If $a > b$, the range is empty, return a null node directly.
Otherwise, we construct a new node $root$, its value is the value of the first node in the pre-order traversal, which is $preorder[a]$.
If $a$ equals $b$, it means that $root$ has neither a left subtree nor a right subtree, return $root$ directly.
Otherwise, the value of the root node of the left subtree is $preorder[a + 1]$, we find the position of $preorder[a + 1]$ in the post-order traversal, denoted as $i$. The number of nodes in the left subtree $m = i - c + 1$, from this we know that the range of the left subtree in the pre-order traversal is $[a + 1, a + m]$, the range in the post-order traversal is $[c, i]$, the range of the right subtree in the pre-order traversal is $[a + m + 1, b]$, and the range in the post-order traversal is $[i + 1, d - 1]$.
Knowing the range of the left and right subtrees, we can recursively rebuild the left and right subtrees, and then make the root nodes of the left and right subtrees as the left and right child nodes of $root$ respectively. Finally return $root$.
In the function $dfs(a, b, c, d)$, we need to use a hash table $pos$, which stores the position of each node in the post-order traversal. At the beginning of the function, we can calculate this hash table first, so that we can find the position of any node in the post-order traversal in $O(1)$ time.
The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes.
1 2 3 4 5 6 7 8 9101112131415161718192021222324
# 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 = rightclassSolution:defconstructFromPrePost(self,preorder:List[int],postorder:List[int])->Optional[TreeNode]:defdfs(a:int,b:int,c:int,d:int)->Optional[TreeNode]:ifa>b:returnNoneroot=TreeNode(preorder[a])ifa==b:returnrooti=pos[preorder[a+1]]m=i-c+1root.left=dfs(a+1,a+m,c,i)root.right=dfs(a+m+1,b,i+1,d-1)returnrootpos={x:ifori,xinenumerate(postorder)}returndfs(0,len(preorder)-1,0,len(postorder)-1)
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */funcconstructFromPrePost(preorder[]int,postorder[]int)*TreeNode{pos:=map[int]int{}fori,x:=rangepostorder{pos[x]=i}vardfsfunc(int,int,int,int)*TreeNodedfs=func(a,b,c,dint)*TreeNode{ifa>b{returnnil}root:=&TreeNode{Val:preorder[a]}ifa==b{returnroot}i:=pos[preorder[a+1]]m:=i-c+1root.Left=dfs(a+1,a+m,c,i)root.Right=dfs(a+m+1,b,i+1,d-1)returnroot}returndfs(0,len(preorder)-1,0,len(postorder)-1)}
We can design a recursive function $dfs(i, j, n)$, where $i$ and $j$ represent the starting points of the pre-order and post-order traversals, respectively, and $n$ represents the number of nodes. This function constructs the root node of the binary tree based on the pre-order traversal $[i, i + n - 1]$ and post-order traversal $[j, j + n - 1]$. The answer is $dfs(0, 0, n)$, where $n$ is the length of the pre-order traversal.
The execution steps of the function $dfs(i, j, n)$ are as follows:
If $n = 0$, the range is empty, so return a null node directly.
Otherwise, we construct a new node $root$, whose value is the value of the first node in the pre-order traversal, which is $preorder[i]$.
If $n = 1$, it means that $root$ has neither a left subtree nor a right subtree, so return $root$ directly.
Otherwise, the value of the root node of the left subtree is $preorder[i + 1]$. We find the position of $preorder[i + 1]$ in the post-order traversal, denoted as $k$. Then the number of nodes in the left subtree is $m = k - j + 1$, and the number of nodes in the right subtree is $n - m - 1$. We recursively rebuild the left and right subtrees, and then make the root nodes of the left and right subtrees the left and right child nodes of $root$, respectively. Finally, return $root$.
The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes.
1 2 3 4 5 6 7 8 9101112131415161718192021222324
# 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 = rightclassSolution:defconstructFromPrePost(self,preorder:List[int],postorder:List[int])->Optional[TreeNode]:defdfs(i:int,j:int,n:int)->Optional[TreeNode]:ifn<=0:returnNoneroot=TreeNode(preorder[i])ifn==1:returnrootk=pos[preorder[i+1]]m=k-j+1root.left=dfs(i+1,j,m)root.right=dfs(i+m+1,k+1,n-m-1)returnrootpos={x:ifori,xinenumerate(postorder)}returndfs(0,0,len(preorder))
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */funcconstructFromPrePost(preorder[]int,postorder[]int)*TreeNode{pos:=map[int]int{}fori,x:=rangepostorder{pos[x]=i}vardfsfunc(int,int,int)*TreeNodedfs=func(i,j,nint)*TreeNode{ifn<=0{returnnil}root:=&TreeNode{Val:preorder[i]}ifn==1{returnroot}k:=pos[preorder[i+1]]m:=k-j+1root.Left=dfs(i+1,j,m)root.Right=dfs(i+m+1,k+1,n-m-1)returnroot}returndfs(0,0,len(preorder))}