从中序遍历和前序遍历构建二叉树
描述:输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]
示例2:
Input: preorder = [-1], inorder = [-1]
Output: [-1]
限制:
0 <= 节点个数 <= 5000
节点定义如下:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
此题与leetcode108. 将有序数组转换为二叉搜索树
有所不同,leetcode108. 将有序数组转换为二叉搜索树在我上篇博客可以看到解法,leetcode108. 将有序数组转换为二叉搜索树
题中给定线性表建立二叉平衡树,只需二分保持左右子树数目大致相等即可,而此题中左右子树的相对关系要从中序与后序中推得。
前序:根–>左–>右
中序:左–>根–>右
基本思路:先从前序序列中得到根节点的值,由于前序和中序都不含重复元素,因此可以得到此时根节点在中序遍历中的索引(可以想到用HashMap来记录值所在的索引),中序序列中小于索引值的元素成为此时根节点的左子树,而大于索引值的元素就成为右子树,此时,需注意的是:中序得到的左子树的索引范围不对应前序所处的左子树范围,中间需计算左子树的元素数量来决定前序遍历左子树的索引范围。
经过上述分析,可以得到构造二叉树所需的参数了,首先,前序序列preorder
、中序序列inorder
、HashMap
(用于记录中序遍历值的索引)、preL
(前序起始索引)、preR
(前序结束索引)、inL
(中序起始索引)、inR
(中序结束索引)
代码如下:
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
public TreeNode dfsTree(int[] preorder, int[] inorder, Map<Integer,Integer> hm, int preL, int preR, int inL, int inR){
if(preL>preR){
return null;
}
int value = preorder[preL]; //前序遍历 首个索引对应的元素即为头节点
int idx = hm.get(value); //在中序哈希表中获得头节点在中序中的索引值,用于划分左右子树
int left_size = idx - inL; //inL为中序遍历起始索引,left_size来记录左子树元素数量,方便后面递归生成左右子树
TreeNode root = new TreeNode(value); //创立头节点
root.left = dfsTree(preorder,inorder,hm,preL+1,preL+left_size,inL,idx-1); //难点在于前序preorder的左子树索引范围,由于根左右的特点,故左子树的范围 =(根节点的索引+1 ,根节点的索引+左子树的大小)
root.right = dfsTree(preorder,inorder,hm,preL+left_size+1,preR,idx+1,inR);//前序右子树的索引范围 = (根节点的索引+左子树的大小+1,末尾索引)
return root;
}
public TreeNode buildTree(int[] preorder, int[] inorder) {
Map<Integer,Integer> hm = new HashMap<>();
for(int i=0;i<inorder.length;i++){
hm.put(inorder[i],i);
}
return dfsTree(preorder,inorder,hm,0,preorder.length-1,0,preorder.length-1);
}
`