一、题目内容
二、题目描述
这两道题目都属于比较经典的构造二叉树的方法,相信大家都可以顺利的在纸上构造完毕。大概步骤如下(以中序+后序为例):
很明显使用递归可以最大程度简化代码量,它的步骤流程是:
(1)如果数组大小为0,直接返回NULL(递归退出条件)
(2)如果不为空,那么当前节点的值取后序数组的最后一个,记为value。
(3)找到后序数组最后一个值在中序数组的位置,记为mid_index。
(4)根据mid_index切割中序数组,mid_index左边的部分递归放在root.left中,右边同理
(5)因为中序数组和后序数组大小相同,以此为条件对后序数组也进行切割。
(6)递归调用左区间和右区间。
(如果是前序+中序,区别就在于当前节点值取的是前序的第一个数)
由此,如果单纯写出代码的话是很容易的。如下:
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if(inorder.length==0||postorder.length==0)
return null;
return travel(inorder,postorder);
}
public TreeNode travel(int[] inorder, int[] postorder){
// 如果数组大小为0,说明为空节点
if(inorder.length==0)
return null;
// 否则,取出后序数组最后一个元素作为节点元素
int last_value = postorder[postorder.length - 1];
// 找到后序数组最后一个元素在中序数组的
TreeNode root = new TreeNode(last_value);
int mid_index = 0;
for(int i = 0; i < postorder.length; i++){
if(inorder[i] == last_value){
mid_index = i;
break;
}
}
int []mid_left = new int[mid_index];
for(int i = 0; i < mid_left.length; i++){
mid_left[i] = inorder[i];
}
int []mid_right = new int[inorder.length - mid_index - 1];
for(int i = 0; i < mid_right.length; i++){
mid_right[i] = inorder[i + mid_left.length + 1];
}
int []last_left = new int[mid_left.length];
int []last_right = new int [mid_right.length];
for(int i = 0; i < last_left.length; i++){
last_left[i] = postorder[i];
}
for(int i = 0; i < last_right.length; i++){
last_right[i] = postorder[i + last_left.length];
}
root.left = travel(mid_left,last_left);
root.right = travel(mid_right,last_right);
return root;
}
}
上述代码使用Java写的,如果使用C++也可以使用vector来储存数据。但是如果大家使用这样的代码提交的话,虽然可以通过,但是效率极低。归根结底是大量的重复对数组的定义和赋值占用了大量的时间和空间。
如果要对其进行简化的话,我觉得可以通过HashMap来解决(总之使用索引代替定义数组)。将中序数组放入HashMap中,key代表中序数组的值,value则是中序数组每个值的下标。这样,递归调用的时候就很方便了。
三、完整代码
// 中序+后序
class Solution {
HashMap<Integer,Integer> memo = new HashMap<>();
int[] post;
public TreeNode buildTree(int[] inorder, int[] postorder) {
for(int i = 0;i < inorder.length; i++) memo.put(inorder[i], i);
post = postorder;
TreeNode root = buildTree(0, inorder.length - 1, 0, post.length - 1);
return root;
}
public TreeNode buildTree(int is, int ie, int ps, int pe) {
if(ie < is || pe < ps) return null;
int root = post[pe];
int ri = memo.get(root);
TreeNode node = new TreeNode(root);
node.left = buildTree(is, ri - 1, ps, ps + ri - is - 1);
node.right = buildTree(ri + 1, ie, ps + ri - is, pe - 1);
return node;
}
}
// 中序+前序
class Solution {
HashMap<Integer,Integer> map = new HashMap<>();
int[] post;
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder.length == 0)
return null;
post = preorder;
for(int i = 0; i < inorder.length; i++){
map.put(inorder[i],i);
}
TreeNode root = buildTree(0,inorder.length-1,0,preorder.length-1);
return root;
}
public TreeNode buildTree(int mid_left,int mid_right,int pre_left,int pre_right){
if(mid_right < mid_left||pre_right<pre_left)
return null;
int root_value = post[pre_left];
int mid_index = map.get(root_value);
TreeNode root = new TreeNode(root_value);
root.left = buildTree(mid_left,mid_index-1,pre_left+1,pre_left+mid_index-mid_left);
root.right = buildTree(mid_index+1,mid_right,pre_left+mid_index-mid_left+1,pre_right);
return root;
}
}
可见效果还是很好的。