首页 > 试题广场 >

将满二叉树转换为求和树

[编程题]将满二叉树转换为求和树
  • 热度指数:13699 时间限制:C/C++ 5秒,其他语言10秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
给出满二叉树的前序遍历结果和中序遍历结果,编写算法将其转化为求和树

什么是求和树:二叉树的求和树, 是一颗同样结构的二叉树,其树中的每个节点将包含原始树中的左子树和右子树的和。

二叉树:

求和树:


二叉树给出前序和中序输入,求和树要求中序输出;
所有处理数据不会大于int;

数据范围:二叉树的节点数满足 ,节点上的值满足

输入描述:
2行整数,第1行表示二叉树的前序遍历,第2行表示二叉树的中序遍历,以空格分割


输出描述:
1行整数,表示求和树的中序遍历,以空格分割
示例1

输入

10 -2 8 -4 6 7 5
8 -2 -4 10 7 6 5

输出

0 4 0 20 0 12 0
import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        List<Integer> list = new ArrayList<>();
        while(sc.hasNext()){
            list.add(sc.nextInt());
        }
        
        int[] preOrder = new int[list.size()/2];
        int[] inOrder = new int[list.size()/2];
        for(int i=0;i<list.size();i++){
            if(i < list.size()/2)
                preOrder[i] = list.get(i);
            else
                inOrder[i-list.size()/2] = list.get(i);
        }
        
        TreeNode root = createTree(preOrder,0,preOrder.length-1,inOrder,0,inOrder.length-1);
        dfs(root);
    }
    //中序遍历输出结果
    public static void dfs(TreeNode root){
        if(root == null)
            return;
        dfs(root.left);
        int num = PrintNode(root);
        System.out.print(num + " ");
        dfs(root.right);
    }
    //打印节点
    public static int PrintNode(TreeNode root){
        if(root == null)
            return 0;
        
        int Left = 0,Right = 0;
        if(root.left != null)
            Left = root.left.val;
        if(root.right != null)
            Right = root.right.val;
        return Left + Right + PrintNode(root.left) + PrintNode(root.right);
    }
    //建树
    public static TreeNode createTree(int[] preOrder,int preStart,int preEnd,int[] inOrder,int inStart,int inEnd){
        
        if(preStart > preEnd || inStart > inEnd)
            return null;
        
        int target = preOrder[preStart];
        TreeNode root = new TreeNode(target);
        int index;
        for(index=inStart;index<=inEnd;index++)
            if(inOrder[index] == target)
                break;
         
        int leftLength = index-inStart;
        root.left = createTree(preOrder,preStart+1,preStart+leftLength,inOrder,inStart,index-1);
        root.right = createTree(preOrder,preStart+leftLength+1,preEnd,inOrder,index+1,inEnd);
        return root;
    }
}
//构造树
class TreeNode{
    int val;
    TreeNode left;
    TreeNode right;
    public TreeNode(int x){val = x;}
}

发表于 2020-05-31 11:00:34 回复(0)
思路和其他人思路一致,只能通过80%,不知道哪里出问题了
import java.util.*;
public class Main{
    static class TreeNode{
        TreeNode left=null;
        TreeNode right=null;
        int val=0;
        public TreeNode(int value){
            val=value;
        }
        public void setValue(int value){
            val=value;
        }
    }
    public static int found(ArrayList<Integer>list,int value){
        for(int i=0;i<list.size();i++){
            if(list.get(i)==value) return i;
        }
        return -1;
    }
    public static TreeNode build(int step,int start,int end,ArrayList<Integer>preList,ArrayList<Integer>midList){
        if(preList.size()==0)return null;
        if(preList.size()<=step)return null;
        TreeNode node=new TreeNode(preList.get(step));
        if(start>=end) return node;
        int mid=found(midList,preList.get(step));
        node.left=build(step+1,start,mid-1,preList,midList);
        node.right=build(step+1+mid-start,mid+1,end,preList,midList);
        return node;
    }
    public static TreeNode buildSum(TreeNode root){
        if(root==null) return null;
        if(root.left==null&&root.right==null) return new TreeNode(0);
        int left=0,right=0;
        TreeNode cur=new TreeNode(0);
        cur.left=buildSum(root.left);
        cur.right=buildSum(root.right);
        root.setValue(root.left.val+root.right.val+root.val);
        if(cur.left!=null) left=root.left.val;
        if(cur.right!=null) right=root.right.val;
        cur.setValue(left+right);
        return cur;
    }
    static ArrayList<Integer>res=new ArrayList<>();
    public static void print(TreeNode root){
        if(root==null) return;
        print(root.left);
        res.add(root.val);
        print(root.right);
    }
    public static void main(String[] args){
        ArrayList<Integer>preList=new ArrayList<>();
        ArrayList<Integer>midList=new ArrayList<>();
        Scanner scanner=new Scanner(System.in);
        String pre="";
        if(scanner.hasNextLine()) {
            pre = scanner.nextLine();
        }
        String mid="";
        if(scanner.hasNextLine()) {
            mid=scanner.nextLine();
        }
        String[] preStr=pre.split(" ");
        String[] midStr=mid.split(" ");
        for(int i=0;i<preStr.length;i++){
            if(!preStr[i].equals("")) {
                preList.add(Integer.parseInt(preStr[i]));
                midList.add(Integer.parseInt(midStr[i]));
            }
        }
        TreeNode tree1=build(0,0,preList.size()-1,preList,midList);
        TreeNode tree=buildSum(tree1);
        print(tree);
        if(res.size()!=0){
            for(int i=0;i<res.size()-1;i++)
                System.out.print(res.get(i)+" ");
            System.out.print(res.get(res.size()-1));
        }
    }
}


发表于 2020-03-02 02:36:30 回复(1)
用了最笨的还原二叉树的方法,才发现有更简单的方法,就当作是练习吧
import java.util.*;
class TreeNode{
    int val;
    TreeNode left = null;
    TreeNode right = null;
    TreeNode(int val) {this.val = val;}
}
public class Main{
    public static void main(String []args){
        Scanner sc = new Scanner(System.in);
        while (sc.hasNextLine()){
            String[] str1 = sc.nextLine().split(" ");
            String[] str2 = sc.nextLine().split(" ");
            int[] pre = new int[str1.length];
            int[] in = new int[str2.length];
            for (int i=0;i<pre.length;i++){
                pre[i] = Integer.valueOf(str1[i]);
                in[i] = Integer.valueOf(str2[i]);
            }
            TreeNode root = reCon(pre, in);
            root = SumTree(root);
            InOrderPrint(root);
        }
    }
    public static void InOrderPrint(TreeNode root){
        if (root == null) return;
        InOrderPrint(root.left);
        System.out.print(root.val+" ");
        InOrderPrint(root.right);
    }
    public static TreeNode reCon(int[] pre, int[] in){
        if (pre.length == 0) return null;
        TreeNode root = new TreeNode(pre[0]);
        for (int i=0;i<in.length;i++)
            if (in[i] == pre[0]){
                root.left = reCon(Arrays.copyOfRange(pre, 1, i+1), Arrays.copyOfRange(in, 0, i));
                root.right = reCon(Arrays.copyOfRange(pre, i+1, pre.length), Arrays.copyOfRange(in, i+1, in.length));
            }
        return root;
    }
    public static TreeNode SumTree(TreeNode root){
        if (root == null) return root;
        TreeNode newroot = new TreeNode(Sum(root)-root.val);
        newroot.left = SumTree(root.left);
        newroot.right = SumTree(root.right);
        return newroot;
    }
    public static int Sum(TreeNode root){
        if (root == null) return 0;
        return root.val+Sum(root.left)+Sum(root.right);
    }
}


发表于 2019-09-24 02:08:28 回复(0)
import java.util.*;
/*
    主要是对于二叉树前序遍历和中序遍历关系转换的理解,对于每个求和节点
    脑海中需要构想出空间位置关系
*/
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        String[] str1 = sc.nextLine().trim().split(" ");
        String[] str2 = sc.nextLine().trim().split(" ");
        
        int[] prevSeq = new int[str1.length];
        int[] inSeq = new int[str2.length];
        boolean[] boolArr = new boolean[str1.length];// 布尔型数组,标记已求和的节点
        int[] inSeqRes = new int[str1.length];    // 记录中序遍历的结果求和树
        
        for(int i = 0;i < prevSeq.length;i++){
            prevSeq[i] = Integer.parseInt(str1[i]);
            inSeq[i] = Integer.parseInt(str2[i]);
        }
        
        for(int i = 0;i < prevSeq.length;i++){
            func(prevSeq[i],inSeq,boolArr,inSeqRes);
        }
        
        for(int i: inSeqRes){
            System.out.print(i+" ");
        }
        System.out.println();
    }
    
    public static void func(int node, int[] inSeq,boolean[] boolArr, int[] inSeqRes){
        int index = -1;// index为在中序遍历中找到的需要求和的节点
        for(int i = 0;i < inSeq.length;i++){
            if(inSeq[i] == node){
                index = i;
                boolArr[index] = true;
                break;
            }
        }
        
        if(index == -1)
            return;// 没有找到就返回
        
        // 对求和节点的左右子树求和
        int sum = 0;
        for(int i = 0;i < index;i++){
            if(boolArr[i]){
                continue;// 对于已经标记的节点(已求和),必定是上层节点,直接跳过
            }
            sum += inSeq[i];
        }
        
        for(int i = index + 1;i < inSeq.length;i++){
            if(boolArr[i]){
                break;
            }
            sum += inSeq[i];
        }
        
        inSeqRes[index] = sum;
    }
}

编辑于 2019-09-16 17:12:31 回复(0)
import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        ArrayList<Integer> preorder  = new ArrayList<>();
        String s = sc.nextLine();
        String[] ss = s.split(" ");
        for(int i = 0 ; i <ss.length;i++){
            preorder.add(Integer.valueOf(ss[i]));
        }
        ArrayList<Integer> inorder = new ArrayList<>();
        s = sc.nextLine();
        ss = s.split(" ");
        for(int i = 0 ; i <ss.length;i++){
            inorder.add(Integer.valueOf(ss[i]));
        }
        getSumTree(preorder,inorder);
        //res = new int[preorder.size()];
        System.out.println(getSumTree(preorder,inorder).trim());
    }
 
    public static String getSumTree(List<Integer> preorder,List<Integer> inorder){
        if(preorder==null||preorder.size()==0)return "";
        if(inorder==null||inorder.size()==0)return "";
        String res = "";
        int root = preorder.get(0);
        int root_idx = 0;
        for(int i = 0 ; i<inorder.size();i++){
            if(inorder.get(i) ==root){
                root_idx = i;
                break;
            }
        }
        res+= getSum(inorder,root_idx);
        //左子树
        res = getSumTree(preorder.subList(1,root_idx+1) , inorder.subList(0,root_idx)) +" "+res;
        //右子树
        res =res + getSumTree(preorder.subList(root_idx+1,preorder.size()) , inorder.subList(root_idx+1,inorder.size()));
        return res;
    }
 
    private static int getSum(List<Integer> inorder, int root_idx) {
        if(inorder==null)return 0 ;
        int sum = 0;
        for(int i = 0 ; i <root_idx;i++)sum+=inorder.get(i);
        for(int i = root_idx+1 ; i <inorder.size();i++)sum+=inorder.get(i);
        return sum;
    }
}

发表于 2019-09-15 20:41:34 回复(0)
//重构二叉树做法
import java.util.*;
class TreeNode{
    int val=0;
    TreeNode left;
    TreeNode right;
    public TreeNode(int val){
        this.val=val;
    }
}
public class Main{
    public static void main(String[]args) {
        Scanner sc = new Scanner(System.in);
        String[] temp = sc.nextLine().split(" ");
        //先序数组
        int[] pre = new int[temp.length];
        for (int i = 0; i < pre.length; i++) {
            pre[i] = Integer.parseInt(temp[i]);
        }
        temp = sc.nextLine().split(" ");
        //中序数组
        int[] mid = new int[temp.length];
        for (int j = 0; j < mid.length; j++) {
            mid[j] = Integer.parseInt(temp[j]);
        }
        //二叉树的根结点
        TreeNode root = arrToTree(pre, 0, pre.length - 1, mid, 0, mid.length - 1);
        //求各个结点的和 
        func(root);
        //中序输出结果
        midOut(root);

    }
    //数组 转成二叉树
    public static TreeNode arrToTree(int []pre,int ps,int pe,int []mid,int ms,int me){
        if(ps>pe||ms>me){
            return null;
        }
        TreeNode node=new TreeNode(pre[ps]);
        for(int i=ms;i<=me;i++){
            if(mid[i]==node.val){
                int len=i-ms;
                node.left=arrToTree(pre,ps+1,ps+len,mid,ms,i-1);
                node.right=arrToTree(pre,ps+len+1,pe,mid,i+1,me);
                break;
            }
        }
        return node;
    }
    //求结点的和  结点的和等于该结点的左、右结点的val+func(左结点)+func(右结点)
    public static int func(TreeNode node){
        if(node==null) return 0;
        int left=0;
        int right=0;
        if(node.left!=null) left=node.left.val;
        if(node.right!=null) right=node.right.val;
        node.val=left+right+func(node.left)+func(node.right);
        return node.val;
    }
    //中序输出
    public static void midOut(TreeNode root){
        if(root.left!=null){
            midOut(root.left);
        }
        System.out.print(root.val+" ");
        if(root.right!=null){
            midOut(root.right);
        }
    }
}
发表于 2019-09-12 15:27:03 回复(0)
卡在了60% 提示数组越界或非法访问,想不出来为什么,求各位大佬帮忙
import java.util.Scanner;

public class Main {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        String[] s = sc.nextLine().split(" "); // 抛弃前序
        int n = s.length;
        int [] nums = new int[n];
        for (int i = 0; i < n; i ++){
            nums[i] = sc.nextInt();
        }
        sum(nums, 0, n-1);

        for(int num : nums)
            System.out.printf("%d ", num);
    }

    /**
     *
     * @param nums 中序遍历
     * @param start 起始下标
     * @param end   终止下标
     */

    public static void sum(int[] nums, int start, int end){
        if (start < 0 || end >= nums.length) return;
        int mid = start + ((end - start) >> 1);
        nums[mid] = 0; // 根结点置为0
        if (start == mid) return;
        for (int i = start, j = end; i < mid; i ++, j --){
            nums[mid] += nums[i] + nums[j];
        }
        // 递归遍历左右子树
        sum(nums, start, mid-1);
        sum(nums, mid+1, end);
    }
}




编辑于 2019-09-06 20:06:06 回复(0)

/*
一开始根据前序和中序, 进行递归, 找出对应的子节点序列, 然后计算, 结果没考虑到重复的情况, 然后被卡在60%, 而后,用完全二叉树的规律对此进行求解 , 发现, 题目是满二叉树, 被卡80%(其实应该是60%, 但是因为一些巧合, 达到了80%, )而后才想出将满二叉树补全为完全二叉树, 得到答案, 甚至有点想奖励自己一个小鸡腿是怎么回事儿
   */

import java.util.*;
public class Main{
     public static void main(String [] args)
        {
            Scanner sc = new Scanner(System.in);
            String s1  = sc.nextLine();    //前序遍历, 改了
            String s2 = sc.nextLine();     //中序遍历
            
            String [] pres = s1.split(" ");
            String [] mids = s2.split(" ");
           int num = ifAll(mids.length);
            int [] pre = new int[pres.length];
            int [] mid = new int[num];    //设置成完全二叉树的样子
            for(int i=0; i<pres.length; i++)
            {
                pre[i]= new Integer(pres[i]);
                mid[i] = new Integer(mids[i]);
               // System.out.println(pre[i] + " " + mid[i]);
              
            }
         
         for(int j = pres.length; j<num; j++)
         {
             mid[j]=0;
         }
            
            //用满二叉树的性质来进行计算
          
                 for(int i=0; i<pre.length; i++)
           {
               if(i%2 == 0)
               {
                   System.out.print("0 ");
               }
               else
               {
                   int l = i-0;
                   int r = mid.length-i-1;
                   int len = l>r?r:l;
                   
                   int sum1 = getSum(mid,i-len ,i-1);
                   int sum2 = getSum(mid,i+1, i+len);
                   
                   int sum =sum1 + sum2;
                   System.out.print( sum + " ");
               }
           }
                
            
        
          
        }
    
    
     public static int getSum(int [] mid, int left, int right)
     {
         int sum = 0;
         for(int i=left; i<=right; i++)
         {
             sum += mid[i];
         }
         return sum;
     }
    //判断它是否为完全二叉树
    public static int ifAll(int num)
    {
        int sum = 1;
      
        int i = 0;
        for(; (sum-1) <= num; i++)
        {
            if((sum-1) == num)
                return num;        //完全二叉树的时候
            sum *= 2;
        }
        //这个时候返回的i是具体的层数
      //  int remain = num - (sum/2-1);    //多出来的部分
        return (sum-1);
            //for(int i=0; i++)
    }
}


发表于 2019-09-06 15:26:49 回复(0)
//只通过60%,没有考虑到节点重复的情况
import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        String s1=sc.nextLine();
        String s2=sc.nextLine();
        String[] str1=s1.split(" ");
        String[] str2=s2.split(" ");
        int[] preorder=new int[str1.length];
        int[] inorder=new int[str2.length];
        int n=preorder.length;
        for(int i=0;i<preorder.length;i++){
            preorder[i]=Integer.parseInt(str1[i]);
            inorder[i]=Integer.parseInt(str2[i]);
        }
        func(preorder,0,n-1,inorder,0,n-1);
        for(int i=0;i<n;i++){
            System.out.print(inorder[i]);
            if(i!=n-1){
                System.out.print(" ");
            }
        }
    }
    public static void func(int[] preorder,int ps,int pl,int[] inorder,int is,int il){
        if(ps==pl){
            inorder[is]=0;
            return;
        }
        int rootVal=preorder[ps];
        int im=is;
        while(im<=il && inorder[im]!=rootVal){
            im++;
        }
        inorder[im]=sum(inorder,is,im-1)+sum(inorder,im+1,il);
        func(preorder,ps+1,ps+im-is,inorder,is,im-1);
        func(preorder,ps+im-is+1,pl,inorder,im+1,il);
    }
    public static int sum(int[] inorder,int s,int l){
        int sum=0;
        for(int i=s;i<=l;i++){
            sum+=inorder[i];
        }
        return sum;
    }
}

发表于 2019-08-05 19:44:25 回复(2)