剑指 Offer 07. 重建二叉树
题目描述:
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点
假设输入的前序遍历和中序遍历的结果中都不含重复的数字
示例1:
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
思路:
由前序遍历和后序遍历的定义可知:
设前序遍历的第一个数字为二叉树的跟节点,设为 x
那么在中序遍历中,在节点 x 左边的数据为 x 的左子树,在节点 x 右边的数据为 x 的右子树
那么,根据上面的想法,我们就可以把一个大问题拆分为多个小问题
我们写一个函数(采用递归的思想),往函数输入中序遍历和后序遍历的结果,那么函数就返回一颗对应的二叉树
函数中,我们可调用函数自身,由于有前序遍历和中序遍历,我们可以确定当前二叉树的根节点,及根节点在中序遍历中的位置。然后我们可想函数传入本节点的左子树对应的中序遍历和前序遍历的范围,那么按照函数的定义,就会返回一颗左子树,右子树也类似。至于如何判断本节点是否有左子树或右子树,只要根据本节点在中序遍历中的位置就可以得出
解题步骤:
-
进行特判及初始化操作
-
编写求二叉树的函数,在函数里面:
-
根据前序遍历,求出当前子树的根节点及其在中序遍历的位置
-
根据根节点在中序遍历的位置,判断是否有左右子树存在
-
如果有左子树或右子树存在,则运用推导出来的公式,将左右子树的前中序遍历的范围写入函数中,求得对应的子树
-
-
返回最终结果
时间复杂度:O(n)
空间复杂度:O(n)
代码:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
int n;
public TreeNode buildTree(int[] preorder, int[] inorder) {
if (preorder.length == 0){ // 特判
return null;
}
TreeNode head = new TreeNode(preorder[0]);
n = preorder.length; // 初始化,n为全局遍历,代表数中节点的总数
build(head, 0, n, 0, n,preorder, inorder);
return head;
}
void build(TreeNode t, int x1, int y1, int x2, int y2, int[] p, int[] ino){
int res = -1;
for (int i = x2; i < y2; i++){
if (p[x1] == ino[i]){ // 查找前序遍历首节点在中序遍历中的位置
res = i;
}
}
if (res - x2 > 0){ // 判断是否有左子树存在
t.left = new TreeNode(p[x1 + 1]);
build(t.left, x1 + 1, x1 + res - x2 + 1, x2, res, p, ino);
}
if (y2 - res > 1){ // 判断是否有右子树存在
t.right = new TreeNode(p[x1 + (res - x2 + 1)]);
build(t.right, x1 + res - x2 + 1, y1, res + 1, y2, p, ino);
}
}
}