Leetcode 106. 从中序与后序遍历序列构造二叉树
给定两个整数数组 inorder
和 postorder
,其中 inorder
是二叉树的中序遍历, postorder
是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
示例 1:
输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3] 输出:[3,9,20,null,null,15,7]
示例 2:
输入:inorder = [-1], postorder = [-1] 输出:[-1]
提示:
1 <= inorder.length <= 3000
postorder.length == inorder.length
-3000 <= inorder[i], postorder[i] <= 3000
inorder
和postorder
都由 不同 的值组成postorder
中每一个值都在inorder
中inorder
保证是树的中序遍历postorder
保证是树的后序遍历
思路:后序遍历是左右根,左右无法确定,只有根是一个节点,是能确定的,必然在后续数组的最右边。然后中序遍历是左右根,当根确定之后,虽然左右子树的具体情况不知道,但是知道左右子树的大体,然后把左右子树,继续当作一个树,继续遍历,知道最后一个节点不再是树,向上放回,递归构造。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
// 中序遍历是左中右,后序遍历是左右中,使用递归,用左右坐标来分割两个数组,每个小数组都是一个小树
// 左右中,这是后序树的数组,那么这个子数组的最后一个元素一定是这个子树的根节点,然后中序序列里找
// 左中右,找到中,就可以分割开左右子树,迭代分割,直到最小子树,无法分割
return buildTreeHelper(inorder, 0, inorder.length-1, postorder, 0, postorder.length-1);
}
public TreeNode buildTreeHelper(int[] inorder, int inStart, int inEnd,int[] postorder, int postStart, int postEnd) {
if (inStart > inEnd || postStart > postEnd) {
return null;
}
// 最后一个必是根节点
int root = postorder[postEnd];
int rootIndex = 0;
// 得到根节点坐标
while (true) {
if (root == inorder[rootIndex]) {
break;
}
rootIndex++;
}
// 只有中序遍历知道左右子树的信息是不够的,还需要让后续遍历知道
int leftLength = rootIndex - inStart;
// 左子树的中序遍历数组起始就是父数组的起始,结束是根节点-1,后序遍历数组的起始就是父数组的起始,结束是父数组起始 + 左子树长度 - 1
TreeNode left = buildTreeHelper(inorder, inStart, rootIndex-1, postorder, postStart, postStart + leftLength-1);
// 右子树的中序遍历数组起始就是根节点+1,结束是父数组的结束,后序遍历数组的起始就是父数组的起始 + 左子树长度,结束是父数组的结束 - 1,减去的这个1就是根节点的长度
TreeNode right = buildTreeHelper(inorder, rootIndex + 1, inEnd, postorder, postStart + leftLength, postEnd-1);
// 然后构造返回
return new TreeNode(root, left, right);
}
}