输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
即返回 [3,9,20,null,null,15,7]
解题是次要的,首先我想说的是,如何确定一颗唯一的二叉树?
先序+中序 or 中序+后序 都是可以的,但是先序+后序不可以(自己简单两个节点试一下就知道了);
其次,二叉树的三个序列中,先序是最具有特征的,因为你能明确根节点是第一个元素,在中序中查找这个元素以此为界限就能明确左右子树以及他们的元素个数,因而对于题干我很快就能知道这样的结构:
接下来就是分治的思想了,如果有了分治把两个子树再单独看作一颗树,继续按照上面思想就能很容易构建出整棵树了
public TreeNode buildTree(int[] preorder, int[] inorder) {
//把前序遍历的值和中序遍历的值放到list中
List<Integer> preorderList = new ArrayList<>();
List<Integer> inorderList = new ArrayList<>();
for (int i = 0; i < preorder.length; i++) {
preorderList.add(preorder[i]);
inorderList.add(inorder[i]);
}
return build(preorderList, inorderList);
}
private TreeNode build(List<Integer> preorderList, List<Integer> inorderList) {
if (inorderList.size() == 0)
return null;
//前序遍历的第一个值就是根节点
int rootVal = preorderList.remove(0);
//创建跟结点
TreeNode root = new TreeNode(rootVal);
//根节点在中序中的位置
int mid = inorderList.indexOf(rootVal);
//中序中[0,mid)是左子树的所有值,包含0不包含mid。
root.left = build(preorderList, inorderList.subList(0, mid));
//中序中[mid+1,inorderList.size())是右子树的所有值,包含mid+1不包含inorderList.size(),因为subList本来就是左闭右开,且数组长度恰好与下标差1
root.right = build(preorderList, inorderList.subList(mid + 1, inorderList.size()));
return root;
}
每次遇到递归我就忍不住推一下以验证它的正确性,首先拿到rootVal=3,定位出mid=1,进入第一层left,此时传入的中序subList(0,1)=[ 9 ]
第一层left rootval=9,定位出mid=0且subList(0,0)=null 进入第二层返回null,并且回到初始层
进入第一层right,此时传入中序subList(2,5)=[ 15,20,7 ]
rootval=20, mid=1,进入第二层left且subList(0,1)=[15]
第二层left,val=15 mid=0 此时subList(0,0)为null进入下一层返回null又回到本层,进入第二层right且中序subList(2,3)=[7]进入下一层返回null又回到本层
,开始逐层确定返回值 7,15,20,9,3分别返回给调用他们的root.left或者root.right,直到返回最后一层也就是buildTree里面最后buid方法的返回值,返回一个root,这个root看似是一个节点,但其实是一整棵树,你懂我意思吗?