Given two integer arrays inorder
and postorder
where inorder
is the inorder traversal of a binary tree and postorder
is the postorder traversal of the same tree, construct and return the binary tree .
Example 1:
Copy Input: inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
Output: [3,9,20,null,null,15,7]
Example 2:
Copy Input: inorder = [-1], postorder = [-1]
Output: [-1]
Constraints:
1 <= inorder.length <= 3000
postorder.length == inorder.length
-3000 <= inorder[i], postorder[i] <= 3000
inorder
and postorder
consist of unique values.
Each value of postorder
also appears in inorder
.
inorder
is guaranteed to be the inorder traversal of the tree.
postorder
is guaranteed to be the postorder traversal of the tree.
Solution:
Very similar to LeetCode 105,
这样的遍历顺序差异,导致了 preorder
和 inorder
数组中的元素分布有如下特点:
这道题和上一题的关键区别是,后序遍历和前序遍历相反,根节点对应的值为 postorder
的最后一个元素。
整体的算法框架和上一题非常类似,我们依然写一个辅助函数 build
:
Copy TreeNode buildTree( int [] inorder , int [] postorder) {
return build(inorder , 0 , inorder . length - 1 ,
postorder , 0 , postorder . length - 1 ) ;
}
TreeNode build( int [] inorder , int inStart , int inEnd ,
int [] postorder , int postStart , int postEnd) {
// root 节点对应的值就是后序遍历数组的最后一个元素
int rootVal = postorder[postEnd];
// rootVal 在中序遍历数组中的索引
int index = 0 ;
for ( int i = inStart; i <= inEnd; i ++ ) {
if (inorder[i] == rootVal) {
index = i;
break ;
}
}
TreeNode root = new TreeNode(rootVal) ;
// 递归构造左右子树
root . left = build(preorder , ? , ? ,
inorder , ? , ? ) ;
root . right = build(preorder , ? , ? ,
inorder , ? , ? ) ;
return root;
}
现在 postoder
和 inorder
对应的状态如下:
我们可以按照上图将问号处的索引正确填入:
Copy int leftSize = index - inStart;
root . left = build(inorder , inStart , index - 1 ,
postorder , postStart , postStart + leftSize - 1 ) ;
root . right = build(inorder , index + 1 , inEnd ,
postorder , postStart + leftSize , postEnd - 1 ) ;
综上,可以写出完整的解法代码:
Copy TreeNode build( int [] inorder , int inStart , int inEnd ,
int [] postorder , int postStart , int postEnd) {
if (inStart > inEnd) {
return null ;
}
// root 节点对应的值就是后序遍历数组的最后一个元素
int rootVal = postorder[postEnd];
// rootVal 在中序遍历数组中的索引
int index = 0 ;
for ( int i = inStart; i <= inEnd; i ++ ) {
if (inorder[i] == rootVal) {
index = i;
break ;
}
}
// 左子树的节点个数
int leftSize = index - inStart;
TreeNode root = new TreeNode(rootVal) ;
// 递归构造左右子树
root . left = build(inorder , inStart , index - 1 ,
postorder , postStart , postStart + leftSize - 1 ) ;
root . right = build(inorder , index + 1 , inEnd ,
postorder , postStart + leftSize , postEnd - 1 ) ;
return root;
}
有了前一题的铺垫,这道题很快就解决了,无非就是 rootVal
变成了最后一个元素,再改改递归函数的参数而已,只要明白二叉树的特性,也不难写出来。
最后呼应下前文,做二叉树的问题,关键是把题目的要求细化,搞清楚根节点应该做什么,然后剩下的事情抛给前/中/后序的遍历框架就行了 。