剑指Offer07重建二叉树
1. 问题描述
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
限制:
0 <= 节点个数 <= 5000
2. 代码实现
2.1 方法一
比较好理解的递归方法
Arrays.copyOfRange(int[] original, int from, int to)
将指定数组的指定范围复制到新数组中。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
// 递归的结束条件
if (preorder == null || preorder.length == 0){
return null;
}
// 1. 获取根节点的val值
TreeNode root = new TreeNode(preorder[0]);
// 2. 获取inorder中序遍历的数组,root节点的下标index
int index = findFirstIndex(preorder,inorder);
/**
* Arrays.copyOfRange(int[] original, int from, int to)
* 将指定数组的指定范围复制到新数组中。
* original - 要从中复制范围的数组
* from - 要复制的范围的初始索引(包括)
* to - 要复制的范围的最终索引,排他。 (该索引可能位于数组之外)
*
* 前序遍历 preorder = [3,9,20,15,7]
* 中序遍历 inorder = [9,3,15,20,7]
* root.val = 3
* index = 1
*
*/
// 3.获取left左子树,需要左子树的前序遍历和中序遍历
root.left = buildTree(Arrays.copyOfRange(preorder,1,index+1),Arrays.copyOfRange(inorder,0,index));
// 4. 获取right右字树,需要右字树的前序遍历和中序遍历
// 因为copyofRange()是包前不包后,所以是inorder.length
root.right = buildTree(Arrays.copyOfRange(preorder,index+1,preorder.length),Arrays.copyOfRange(inorder,index+1,inorder.length));
return root;
}
/**
* 获取每一个子树的根节点,在inorder的下标
* @param preorder
* @param inorder
* @return
*/
public int findFirstIndex(int[] preorder,int[] inorder){
for (int i = 0; i < inorder.length; i++) {
if (inorder[i] == preorder[0]){
return i;
}
}
return 0;
}
}
2.2 方法二
递归法,与方法一的关键思路一样。
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
// 如果输入的前序遍历为空,则直接返回
if (preorder == null || preorder.length == 0) {
return null;
}
// 用来储存中序遍历的下标和val
Map<Integer, Integer> indexMap = new HashMap<Integer, Integer>();
// 获得节点的个数
int length = preorder.length;
// 以值为key,以inorder的下标为value
for (int i = 0; i < length; i++) {
indexMap.put(inorder[i], i);
}
// 调用递归的方法
TreeNode root = buildTree(preorder, 0, length - 1,
inorder, 0, length - 1,
indexMap);
return root;
}
/**
*递归的方法
*/
public TreeNode buildTree(int[] preorder, int preorderStart, int preorderEnd,
int[] inorder, int inorderStart, int inorderEnd,
Map<Integer, Integer> indexMap) {
// 递归结束条件
if (preorderStart > preorderEnd) {
return null;
}
// 拿到inorder中序遍历根节点的val
int rootVal = preorder[preorderStart];
// 创建root节点
TreeNode root = new TreeNode(rootVal);
//
if (preorderStart == preorderEnd) {
return root;
} else {
// 获得root节点的在inorder中的index
int rootIndex = indexMap.get(rootVal);
int leftNodes = rootIndex - inorderStart;
int rightNodes = inorderEnd - rootIndex;
TreeNode leftSubtree = buildTree(
preorder, preorderStart + 1, preorderStart + leftNodes,
inorder, inorderStart, rootIndex - 1,
indexMap);
TreeNode rightSubtree = buildTree(
preorder, preorderEnd - rightNodes + 1,
preorderEnd, inorder, rootIndex + 1,
inorderEnd, indexMap);
root.left = leftSubtree;
root.right = rightSubtree;
return root;
}
}
}
3.测试结果
方法一:
- 执行用时:14 ms, 在所有 Java 提交中击败了16.86%的用户
- 内存消耗:90.7 MB, 在所有 Java 提交中击败了11.74%的用户
方法二:
- 执行用时:3 ms, 在所有 Java 提交中击败了83.09%的用户
- 内存消耗:40 MB, 在所有 Java 提交中击败了60.04%的用户