输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
示例 1:
输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]
示例 2:
输入: preorder = [-1], inorder = [-1]
输出: [-1]
限制:
- 0 <= 节点个数 <= 5000
分析:
先序遍历的形式是:根节点 - 左子树先序遍历结果 - 右子树先序遍历结果
中序遍历的形式是:左子树中序遍历结果 - 根节点 - 右子树中序遍历结果
方法1:分治算法
由先序遍历的形式可以知道,先序数组的第一个一定为根节点,那么我们可以根据这个根节点找到中序数组对应根节点的索引,根据这个索引,我们可以知道左右子树的长度以及在中序数组对应的范围,根据左右子树的长度,我们又可以知道先序数组对应左右子树的范围,从而知道左右子树的根节点,然后我们根据这根节点继续执行相同操作就可以得到重建二叉树了。
时间复杂度:O(n^2)
空间复杂度:O(n)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
//记录数组长度
int len;
//先序和中序数组
int[] preorder, inorder;
public TreeNode buildTree(int[] preorder, int[] inorder) {
len = preorder.length;
//空数组直接返回空
if(len == 0){
return null;
}
this.preorder = preorder;
this.inorder = inorder;
//重建二叉树
TreeNode root = buildTree(0, len, 0);
return root;
}
public TreeNode buildTree(int i, int j, int k){
//创建当前位置对应数组节点
TreeNode node = new TreeNode(preorder[k]);
//记录根节点位置
int root = 0;
//遍历寻找根节点位置
for(int a = i; a < j; a++){
if(inorder[a] == preorder[k]){
root = a;
break;
}
}
//先序遍历根节点一般为下一个左根节点,所以执行加一操作,后面在判断是不是为左节点
k++;
//进行下一层根节点操作
//判断是否有左根节点
if(root > i){
node.left = buildTree(i, root, k);
}
//判断是否有右节点
if(1 + root < j && k+root-i < len){
node.right = buildTree(root+1, j, k+root-i);
}
return node;
}
}
方法2: 分治算法+HashMap
如果按照方法 1 ,每一次递归都要在中序遍历数组中找一次根节点索引,浪费时间,因为题目的条件提到遍历的结果不包含重复数字,那么可以利用 HashMap 来存储中序遍历数组的索引,数字作为键值,那么每一次递归直接根据数字就可以找到对应根节点索引。
时间复杂度:O(n)
空间复杂度:O(n)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
//记录数组长度
int len;
//先序
int[] preorder;
//利用HashMap记录中序
HashMap<Integer, Integer> map;
public TreeNode buildTree(int[] preorder, int[] inorder) {
len = preorder.length;
//空数组直接返回空
if(len == 0){
return null;
}
this.preorder = preorder;
map = new HashMap<>();
//因为数字不重复,所以可以将数字作为键,索引作为值
for(int i = 0; i < len; ++i){
map.put(inorder[i], i);
}
//重建二叉树
TreeNode root = buildTree(0, len, 0);
return root;
}
public TreeNode buildTree(int i, int j, int k){
//创建当前位置对应数组节点
TreeNode node = new TreeNode(preorder[k]);
//记录根节点位置
int root = map.get(preorder[k]);
//先序遍历根节点一般为下一个左根节点,所以执行加一操作,后面在判断是不是为左节点
k++;
//进行下一层根节点操作
//判断是否有左根节点
if(root > i){
node.left = buildTree(i, root, k);
}
//判断是否有右节点
if(1 + root < j && k+root-i < len){
node.right = buildTree(root+1, j, k+root-i);
}
return node;
}
}
题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof