剑指 Offer 07. 重建二叉树
题目:
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/
9 20
/
15 7
限制:
0 <= 节点个数 <= 5000
思路:
1.先序数组的首位是根节点,根节点在中序数组中左边的是左子树,右边的是右子树。
2.root+左子树的节点个数在先序数组中的数量对应的数组就是左子树的先序数组,剩下的就是右子树的先序数组
3.按照此规律递归
代码:
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if (preorder.length <= 0 && inorder.length <= 0) {
return null;
}
// 1、找出根节点
int mid = 0;
for (int i = 0; i < inorder.length; i++) {
if (preorder[0] == inorder[i]) {
mid = i;
break;
}
}
// 2、构造出新的数组
int[] inleft = new int[mid];
int[] inright = new int[inorder.length - mid - 1];
for (int j = 0; j < inorder.length; j++) {
if (j < inleft.length) {
inleft[j] = inorder[j];
}
if(j < inright.length){
inright[j] = inorder[mid + j + 1];
}
}
int[] preleft = new int[mid];
int[] preright = new int[preorder.length - mid - 1];
for (int i = 0; i < preorder.length; i++) {
if (i < preleft.length) {
preleft[i] = preorder[i + 1];
}
if (i < preright.length) {
preright[i] = preorder[i + mid + 1];
}
}
// 3、递归返回
TreeNode root = new TreeNode(preorder[0]);
// 错误,应该使用递归返回。
// TreeNode left = null;
// TreeNode right = null;
// if (mid - 1 > 0) {
// left = new TreeNode(inorder[mid - 1]);
// }
// if (mid < inorder.length - 1) {
// right = new TreeNode(preorder[mid + 1]);
// }
root.left = buildTree(preleft, inleft);
root.right = buildTree(preright, inright);
return root;
}
}
结果是这样的:
应该是每次都new的新的数组,如果使用已经提供的数组,只是改变index,应该会有比较明显的改善:
/**
* 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) {
return dosome(preorder,inorder,0,preorder.length-1,0,inorder.length-1);
}
private TreeNode dosome(int[] preorder, int[] inorder, int prehead, int pretail, int inhead, int intail) {
if (inhead >= inorder.length || prehead>=preorder.length || prehead > pretail || inhead > intail) {
return null;
}
//找出中位计算数组的长度。
int mid = inhead;
for (int i = inhead; i <= intail; i++) {
if (inorder[i] == preorder[prehead]) {
mid = i;
}
}
// 不在这减,就要在递归方法中减。计算数组的长度:mid - inhead。(数组长度是通过中序得到的)
mid -= inhead;
// [1],[2,4,7],[3,5,6,8]
// [4,7,2],[1],[5,3,8,6]
// 直接根据第一次的找规律,递归越深反而不好找了。
TreeNode root = new TreeNode(preorder[prehead]);
TreeNode left = dosome(preorder, inorder, prehead + 1, prehead + mid, inhead, inhead + mid - 1);
//TreeNode right = dosome(preorder, inorder, pretail - mid, pretail, intail - mid, intail);
TreeNode right = dosome(preorder, inorder, prehead + mid + 1, pretail, inhead + mid + 1, intail);
root.left = left;
root.right = right;
return root;
}
}
内存有明显的改善,时间也有部分的增强
关于第二个记录下自己的问题
1、主要是第一次做将mid作为index,所以递归参数怎么都想不出来
2、将mid作为长度,递归参数就十分好想了,直接利用第一次分治就可以写出来
3、mid -= inhead 是关键!