根据一棵树的中序遍历与后序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
因为后序遍历的顺序是(左,右,根),最后一个节点总是根节点,而中序遍历的顺序是(左,根,右),我们可以先根据根节点将中序遍历分为左、右两棵子树,再分别递归地处理他们。
重点是怎么正确的把数组分开。这个看注释吧~
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
int[] inorder;
int[] postorder;
public TreeNode buildTree(int[] inorder, int[] postorder) {
this.inorder = inorder;
this.postorder = postorder;
return buildTree(0, inorder.length, 0, postorder.length);
}
public TreeNode buildTree(int inL, int inR, int postL, int postR) {
if (inL == inR) return null;
// 倒序遍历 postorder数组,第一个在 inorder[inL,inR)内的值就是根节点
// pivot为根节点的值,i与 j分别是根节点在 inorder与 postorder中的索引
boolean find = false;
int i = 0, j = postR - 1;
for ( ; j >= 0; j--) {
for ( i = inL; i < inR; i++) {
if (inorder[i] == postorder[j]) {
find = true;
break;
}
}
if (find) break;
}
int pivot = inorder[i];
// 因为 i是根节点的索引,将 [inL, inR)拆分成 [inL, i)左子树,[i+1, inR)右子树
// 因为 j是根节点的索引,所以左右子树都在根节点的左边,将 [postL, postR)缩至 [postL, j)
// 注意 j-1的值不一定在拆分的inorder数组内,毕竟 [inL, i)左子树,[i+1, inR)右子树都是 [postL, j)的子集
// 所以有上面的遍历,从j往前倒序遍历,第一个在inorder的数组内的一定是根节点
TreeNode root = new TreeNode(pivot);
root.left = buildTree(inL, i, postL, j);
root.right = buildTree(i + 1, inR, postL, j);
return root;
}
}