剑指 Offer 07. 重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
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]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof
题解如下:
首先重建二叉树需要什么?
必然是 根节点,左子树,右子树
怎么找到我们需要的节点?
前序遍历:根节点–左子树–右子树
中序遍历:左子树–根节点–右子树
第一个根节点必然出现在前序遍历的第一个位置!但是对于中序遍历来说,我们不知道第一个根前面左子树的长度,所以无法得知!因此最简单的切入点就是通过前序遍历找到第一个根节点
如何找到第一个左节点?
这个在前序遍历中也很好看出来,第一个左节点就在第一个根节点的右边1个单位,即:pre_root_index + 1
如何找到第一个右节点?
我们找到了第一个根,第一个左节点,那如何确定第一个右节点呢?
对于前序遍历而言,我们已经知道了根、左节点,那么很显然,右节点的下标 = 根节点下标 + 左子树的长度 + 1(在前序遍历数组中),现在唯一不确定的就是左子树的长度,这一点可以很简单的从中序遍历中获得,也就是左子树长度 = 根节点下标 - 左子树的左边界 (在中序遍历数组中)
现在我们就重建完一个最基础的二叉树了~
那如何得到一颗完整的二叉树,这里就是递归啦,注意三个要素即可:
出口条件
此次递归要做什么
返回值
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
this.preorder = preorder ;
this.inorder = inorder;
//空间换时间思想 避免每次查找都要遍历,时间复杂度O(1)
for (int i = 0; i < inorder.length; i++) {
map.put(inorder[i],i);
}
return backtrace(0,0,inorder.length-1);
}
int[] preorder, inorder;
HashMap<Integer, Integer> map = new HashMap<>();
public TreeNode backtrace(int pre_root_index,int in_left_index,int in_right_index){
if (in_left_index > in_right_index) return null;
//需要知道根节点在中序遍历的位置 因为map中存的是inorder的键值对,
// 所以用preorder的根节点位置去查找在中序遍历中的根节点位置
int in_root_index = map.get(preorder[pre_root_index]);
//根节点
TreeNode node = new TreeNode(preorder[pre_root_index]);
// 寻找node的左节点:
// 在前序遍历中的位置就是 根节点的下标 + 1(右边一个单位)
// 我们要定位在中序遍历当中的左节点位置就需要通过更新前序遍历的左节点值去找
// 在中序遍历中的位置就是: 1. 左边界不变,2. 右边界就是根节点的左边一个单位 in_root_index - 1
node.left = backtrace(pre_root_index+1,in_left_index,in_root_index-1);
//找右节点
//找到在前序遍历当中左节点的位置 是根节点的下标 + 左子树长度 + 1
// 因为左子树长度我们不知道 所以通过右子树去求左子树长度 即根节点减去左边界就知道长度了 in_root_index - in_left_index
// 在中序遍历中的位置就是: 1. 左边界在根节点的右边一个单位 in_root_index + 1, 2. 右边界不变
node.right = backtrace(pre_root_index+in_root_index-in_left_index+1,in_root_index+1,in_right_index);
return node;
}
}
算法笔记:
**有错误请在下方指出 谢谢**