【大厂真题-京东】

一、真题描述

牛牛的糖果树

牛牛的朋友送了她一棵节点数为 n 的糖果树(1号点为根节点),树上的每个糖果都有一个颜色。

牛牛吃糖果有一个习惯,她每次都会吃掉一整个子树的糖果,她喜欢与众不同,所以每次吃之前她都会把出现次数最多的颜色的糖果扔掉(可能有多个出现次数最多的颜色,此时要全部扔掉),她可以选择任意一棵子树吃掉,但她只能吃一次,因此他想知道她一次能吃到的所有糖果的颜色的异或和最大是多少(如果吃到了多个颜色相同的糖果,也需要做多次异或),你能帮帮她吗?              

时间限制:C/C++ 1秒,其他语言2秒

空间限制:C/C++ 256M,其他语言512M

输入输出描述:

 

示例1:

输入例子:4
1 2 3 4

1 2

2 3

2 4

输出例子:0

例子说明:四个节点颜色各不相同。吃掉任意子树都会在吃之前把所有糖果扔掉,因此结果为0。

示例2:

输入例子:

4
1 1 2 2 
1 2
2 3 
2 4

输出例子:1

例子说明:

吃掉以节点3或节点4为根的子树都只有一个节点,结果都为0,以1为根节点时颜色为1和颜色为2的节点数量都为2,因此结果也为0。吃掉以2为根的子树时节点3和节点4颜色都为2被删除,结果为节点2的颜色1。

二、解题思路&答案

解题思路:

  1. 树的构建

    • 使用邻接表存储树的结构。
    • 节点编号从 1 到 n,其中 1 是根节点。
  2. DFS 遍历

    • 使用递归的方式对树进行深度优先遍历。
    • 每个节点返回两个信息:
      • colorCount:该子树中每种颜色的出现次数(Map<Integer, Integer>)。
      • totalXor:该子树中所有糖果颜色的异或和(未移除任何颜色)。
  3. 合并子树信息

    • 合并所有子节点的颜色统计,得到当前节点的完整颜色分布。
    • 合并所有子节点的异或和,并加上当前节点的颜色。
  4. 计算最大异或和

    • 找出当前子树中出现次数最多的颜色集合。
    • 对这些颜色进行处理:若出现次数为奇数次,则异或其颜色值。
    • 从 totalXor 中减去这些异或值,得到最终的异或和。
    • 更新全局最大异或和。

代码实现:

java:

import java.util.*;

public class CandyTree {
    static int[] color;
    static List<List<Integer>> adj;
    static int maxXor;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        color = new int[n + 1]; // 1-based indexing

        // Read colors
        for (int i = 1; i <= n; i++) {
            color[i] = scanner.nextInt();
        }

        // Build adjacency list
        adj = new ArrayList<>();
        for (int i = 0; i <= n; i++) {
            adj.add(new ArrayList<>());
        }

        for (int i = 0; i < n - 1; i++) {
            int u = scanner.nextInt();
            int v = scanner.nextInt();
            adj.get(u).add(v);
            adj.get(v).add(u);
        }

        maxXor = 0;
        dfs(1, -1);
        System.out.println(maxXor);
    }

    static class Result {
        Map<Integer, Integer> colorCount;
        int totalXor;

        Result(Map<Integer, Integer> colorCount, int totalXor) {
            this.colorCount = colorCount;
            this.totalXor = totalXor;
        }
    }

    static Result dfs(int node, int parent) {
        Map<Integer, Integer> colorCount = new HashMap<>();
        int totalXor = 0;

        for (int neighbor : adj.get(node)) {
            if (neighbor != parent) {
                Result childRes = dfs(neighbor, node);

                // Merge child's colorCount
                for (Map.Entry<Integer, Integer> entry : childRes.colorCount.entrySet()) {
                    int c = entry.getKey();
                    int cnt = entry.getValue();
                    colorCount.put(c, colorCount.getOrDefault(c, 0) + cnt);
                }

                // Merge child's XOR
                totalXor ^= childRes.totalXor;
            }
        }

        // Add current node's color
        int currentColor = color[node];
        colorCount.put(currentColor, colorCount.getOrDefault(currentColor, 0) + 1);
        totalXor ^= currentColor;

        // Find maximum frequency
        int maxCount = 0;
        for (int cnt : colorCount.values()) {
            if (cnt > maxCount) {
                maxCount = cnt;
            }
        }

        // Collect colors with max frequency
        List<Integer> colorsToRemove = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : colorCount.entrySet()) {
            if (entry.getValue() == maxCount) {
                colorsToRemove.add(entry.getKey());
            }
        }

        // Compute removeXor
        int removeXor = 0;
        for (int c : colorsToRemove) {
            int cnt = colorCount.get(c);
            if (cnt % 2 == 1) {
                removeXor ^= c;
            }
        }

        // Compute final XOR
        int currentFinalXor = totalXor ^ removeXor;
        if (currentFinalXor > maxXor) {
            maxXor = currentFinalXor;
        }

        return new Result(colorCount, totalXor);
    }
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值