题目:
给定一个前序遍历生成的数组和一个中序遍历生成的数组来确定这个二叉树的结构,并构造出来
本题解用的是递归方法
思路:
首先我们要理解前序遍历和中序遍历的意义。
前序遍历节点依次为:头节点,左子树节点,右子树节点
中序遍历节点依次为:左子树节点,头节点,右子树节点
- 根据前序遍历思想,我们可知第一个节点一定是头节点,但是我们不知道该节点后面哪几个是左子树的,哪几个是右子树的节点
- 而对于中序遍历来说,如果找到头节点,那么左边的节点一定都是左子树节点
- 因此将二者各自的优势结合,我们可以通过前序遍历先找到头节点,再通过头节点在中序遍历找到左子树的值
- 我们可以设置一个HashMap集合
indexMap
来存放每个TreeNode
节点,key
值为节点的值,而value
值为该节点在中序遍历中的索引位置 - 主函数:通过递归先将前序遍历的第一个节点设置为
root
,通过前面设置的map集合indexMap
找到该节点在中序遍历中的位置,就可以确定该节点左子树有几个节点了,设置一个变量leftNum
接收它 - 然后通过递归求左子树和右子树的节点,最后返回
root
以下为代码+注释,看代码应该比较好理解一点,我的思路基本全在注释里面了
//首先定义TreeNode节点
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int val){
this.val = val;
}
}
public TreeNode buildTree(int[] preorder, int[] inorder){
int len = inorder.length;
//设置一个indexMap存储每个节点在中序遍历中的位置
indexMap = new HashMap<>();
for(int i = 0; i < len; i++){
indexMap.put(inorder[i], i);
}
return dfs(preorder, 0, len, inorder, 0, len);
}
//递归函数,传入前序和中序遍历的数组以及当前层递归中
//前序和中序遍历数组的开始索引以及结束索引
//注意!!!!包含头部,不包含尾部索引!(也就是到end索引前面那一个)
public TreeNode dfs(int[] preorder, int pre_begin, int pre_end,
int[] inorder, int in_begin, int in_end){
if(pre_begin == pre_end)
return null;
TreeNode root = new TreeNode(preorder[pre_begin]);
// 通过中序遍历找到根节点的索引位置
int in_root_index = indexMap.get(preorder[pre_begin]);
// 左子树的节点个数
int leftNum = in_root_index - in_begin;
// 递归求出左子树节点和右子树节点,关键后面几个索引不要搞错!
// 首先求当前节点的左子树节点
// 前序数组的开始索引表示头节点后面第一个左子树节点索引位置,
// 结尾索引为第一个左子树节点+前面计算过的leftNum
// 这就囊括了当前节点的所有左子树节点
// 而中序数组的开始索引就是in_bein,因为左子树节点在根节点左边
// 结束索引为根节点的下一个也就是in_root_index+1
root.left = dfs(preorder, pre_begin + 1, pre_begin + leftNum + 1,
inorder, in_begin, in_root_index);
// 然后求当前节点的右子树节点,索引设置同上面求左子树节点
root.right = dfs(preorder, pre_begin + leftNum + 1, pre_end,
inorder, in_root_index + 1, in_end);
// 最后返回root即为所求结果
return root;
}
第一次接触该题如果不理解很正常,结合前序和中序遍历特性反复看两遍,相信一定能有所收获~
笔者也在不断学习当中,如有错误,欢迎指正!