华为2021年9月8日机试第一题

题目:
【问题】
给出一颗二叉树,每个节点有一个编号和一个值,该值可能为负数,请你找出一个最优节点(除根节点外),使得在该节点将树分成两棵树后(原来的树移除这个节点及其子节点,新的树以该节点为根节点),分成的两棵树各 节点的和之间的差绝对值最大。请输出该节点编号,如有多个相同的差,输出编号最小的节点。
【输入】
4
4 9 -7 -8
0 1
0 3
1 2
第一行,四个节点,编号0-3,范围为1-10000
第二行,节点0-3的权值
第三行到第五行,表示二叉树各节点间的父子关系
0 1 // 节点0的左节点是1
0 3 // 节点0的右节点是3
1 2 // 节点1的左节点是2
注意:左节点永远出现在右节点之前
0:4
/
1:9 3:-8
/
2:-7
【输出】
节点编号,示例中编号为3的节点是最优节点

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;


public class Huawei090801 {

    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // n 个数
        int n= Integer.parseInt(br.readLine());

        // n 个节点
        Node[] nodes= new Node[n];

        String[] s = br.readLine().split(" ");

        // N 个节点的总值
        int sum=0;

        for (int i = 0; i < n; i++) {
            // 构造每一个节点
           nodes[i]=new Node(i,Integer.parseInt(s[i]));
           sum+=Integer.parseInt(s[i]);
        }


        // n个节点,有n-1个数据对,进行对二叉树的构造
        for (int i = 0; i < n-1; i++) {
            String[] s1=br.readLine().split(" ");
            // 该节点的id值
            int r=Integer.parseInt(s1[0]);
            // 该节点的左孩子或者右孩子的id值
            int child=Integer.parseInt(s1[1]);

            if(nodes[r].left==null){
                nodes[r].left=nodes[child];
            }else{ // nodes[r].right==null
                nodes[r].right=nodes[child];
            }
        }

        // 开始计算
        // 根节点是id为0的节点
        Node root=nodes[0];

        int[] sums= new int[n];

        for (int i = 1; i < n; i++) {
            // 得到从1开始以该节点为跟的所有值的总和
            sums[i]=getSum(nodes[i]);
        }

        // 计算左右两个子树和之差的绝对值
        int[] absSum= new int[n];

        for (int i = 1; i < n; i++) {
            absSum[i]=Math.abs(sums[i]-(sum-sums[i]));
        }

        // 遍历得到最大的id值
        int resId=0;
        int max=Integer.MIN_VALUE;
        for (int i = 1; i < n; i++) {
            if(absSum[i]>max){
                resId=i;
                max=absSum[i];
            }
        }

        System.out.println(resId);
    }

    // 采用层序遍历的方式
    private static int getSum(Node node){

        int sum=0;
        Queue<Node> queue= new LinkedList<>();
        queue.add(node);
        while(!queue.isEmpty()){
            Node remove = queue.remove();
            sum+=remove.val;
            if(remove.left!=null){
                queue.add(remove.left);
            }
            if(remove.right!=null){
                queue.add(remove.right);
            }
        }
        return sum;
    }

    // 定义节点的内部类
    static class Node{

        public Node left;
        public Node right;
        public int val;
        public int id;

        public Node(int id,int val,Node left,Node right){
            this.id=id;
            this.val=val;
            this.left=left;
            this.right=right;
        }

        public Node(int id,int val){
            this(id,val,null,null);
        }
    }
}
  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肖大仙~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值