题目
根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
思路
先序遍历的第一个元素即为树的根节点。中序遍历被这个根节点分为两部分,左边部分在根节点左边,右边部分在根节点右边。分别在左边部分和右边部分找到它们的根结点(在先序遍历中位置最前的那个元素即为根节点)。如此递归下去。递归参数:根节点,被根结点拆分的数组。递归方法:根据根节点将数组拆分,并分别找出拆分部分的根节点,再递归。
代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public static Map<Integer,Integer> map;
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder.length==0){
return null;
}
//将前序中的值与位置存储到map中,用空间代价减少时间代价,减少了一个for循环的复杂度
map = new HashMap<Integer, Integer>();
for(int i=0;i<preorder.length;i++){
map.put(preorder[i], position_of_order(preorder,preorder[i]));
}
TreeNode rootnode=new TreeNode(preorder[0]);
digui(rootnode,inorder,preorder);
return rootnode;
}
public void digui(TreeNode zhongfennode,int[] inorder,int[] preorder){
if(inorder.length==1){
return;
}
int position=position_of_order(inorder,zhongfennode.val);
//zhongfennode在最左边
if(position==0){
int[] right=new int[inorder.length-position-1];
int rightnodeindex=-1;
for(int i=0;i<inorder.length-position-1;i++){
right[i]=inorder[i+position+1];
if(rightnodeindex==-1){
//rightnodeindex=position_of_order(preorder,right[i]);
//上面换成下面,减少了一个for循环的复杂度
rightnodeindex=map.get(right[i]);
}else{
// if(position_of_order(preorder,right[i])<rightnodeindex){
// rightnodeindex=position_of_order(preorder,right[i]);
// }
//上面换成下面,减少了一个for循环的复杂度
if(map.get(right[i])<rightnodeindex){
rightnodeindex=map.get(right[i]);
}
}
}
TreeNode rightnode=new TreeNode(preorder[rightnodeindex]);
zhongfennode.right=rightnode;
digui(rightnode,right,preorder);
}else if(position==inorder.length-1){
//zhongfennode在最右边
int[] left=new int[position];
int leftnodeindex=-1;
for(int i=0;i<position;i++){
left[i]=inorder[i];
if(leftnodeindex==-1){
//leftnodeindex=position_of_order(preorder,left[i]);
//上面换成下面,减少了一个for循环的复杂度
leftnodeindex=map.get(left[i]);
}else{
// if(position_of_order(preorder,left[i])<leftnodeindex){
// leftnodeindex=position_of_order(preorder,left[i]);
// }
//上面换成下面,减少了一个for循环的复杂度
if(map.get(left[i]) <leftnodeindex){
leftnodeindex=map.get(left[i]); ;
}
}
}
TreeNode leftnode=new TreeNode(preorder[leftnodeindex]);
zhongfennode.left=leftnode;
digui(leftnode,left,preorder);
}else{
//zhongfennode在中间某位置
int[] left=new int[position];
int leftnodeindex=-1;
int[] right=new int[inorder.length-position-1];
int rightnodeindex=-1;
for(int i=0;i<position;i++){
left[i]=inorder[i];
if(leftnodeindex==-1){
//leftnodeindex=position_of_order(preorder,left[i]);
//上面换成下面,减少了一个for循环的复杂度
leftnodeindex=map.get(left[i]);
}else{
// if(position_of_order(preorder,left[i])<leftnodeindex){
// leftnodeindex=position_of_order(preorder,left[i]);
// }
//上面换成下面,减少了一个for循环的复杂度
if(map.get(left[i]) <leftnodeindex){
leftnodeindex=map.get(left[i]); ;
}
}
}
for(int i=0;i<inorder.length-position-1;i++){
right[i]=inorder[i+position+1];
if(rightnodeindex==-1){
//rightnodeindex=position_of_order(preorder,right[i]);
//上面换成下面,减少了一个for循环的复杂度
rightnodeindex=map.get(right[i]);
}else{
// if(position_of_order(preorder,right[i])<rightnodeindex){
// rightnodeindex=position_of_order(preorder,right[i]);
// }
//上面换成下面,减少了一个for循环的复杂度
if(map.get(right[i])<rightnodeindex){
rightnodeindex=map.get(right[i]);
}
}
}
TreeNode leftnode=new TreeNode(preorder[leftnodeindex]);
zhongfennode.left=leftnode;
digui(leftnode,left,preorder);
TreeNode rightnode=new TreeNode(preorder[rightnodeindex]);
zhongfennode.right=rightnode;
digui(rightnode,right,preorder);
}
}
public int position_of_order(int[] order,int val){
for(int i=0;i<order.length;i++){
if(order[i]==val){
return i;
}
}
return 0;
}
}
注意
第一次写的代码为注释掉的代码,超时。为了解决超时的问题,引入map类型,将for循环得到的值存到map中,用空间代价减少时间代价。
思路2
外层循环遍历先序数组,第一个元素为根节点。第二元素与第一个元素在中序数组的位置进行比较,判断位置在根结点的左还是右。第三个元素与第一个元素在中序数组的位置进行比较,假如在左,判断第一个元素左侧是否为空,若为空则将第三个元素放在此处,若不为空,第三个元素再次与第一个元素左侧这个元素进行第二轮比较。。。以此类推。
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder.length==0){
return null;
}
TreeNode[] treenodes=new TreeNode[preorder.length];
for(int i=0;i<preorder.length;i++){
treenodes[i]=new TreeNode(preorder[i]);
}
for(int i=1;i<preorder.length;i++){
for(int j=0;j<i;j++){
if(position_of_order(inorder,preorder[i])<position_of_order(inorder,preorder[j])){
if(treenodes[j].left==null){
treenodes[j].left=treenodes[i];
break;
}else{
j=position_of_order(preorder,treenodes[j].left.val)-1;
}
}else{
if(treenodes[j].right==null){
treenodes[j].right=treenodes[i];
break;
}else{
j=position_of_order(preorder,treenodes[j].right.val)-1;
}
}
}
}
return treenodes[0];
}
public int position_of_order(int[] order,int val){
for(int i=0;i<order.length;i++){
if(order[i]==val){
return i;
}
}
return 0;
}
}
注意
超时,可利用map类型,减少一个for循环,用空间代价减少时间代价。