欢迎光临
我们一直在努力

千问 LeetCode 3068. 最大节点价值之和 Java实现

这是一道非常经典的结合了图论性质与贪心算法的题目。以下是详细的思路解析与 Java 代码实现。

核心思路分析

1. 挖掘树的隐藏性质(脑筋急转弯):
   题目规定每次操作必须选择一条边,将相连的两个节点同时异或 k。但深入思考会发现,树中任意两个节点之间都存在唯一一条路径。如果我们对这条路径上的所有边都进行一次异或操作,最终的结果是:只有路径两端的节点被异或了一次 k,而路径中间的所有节点都被异或了两次(根据异或性质 x ^ k ^ k = x,中间节点的值保持不变)。
   
   由此得出关键结论:我们可以任选任意两个节点,使它们的值同时异或一次 k。因此,题目中的 edges 数组实际上是一个干扰项,我们可以完全忽略它。

2. 转化为差值最大化问题:
   既然可以任选两个节点进行异或,且每次操作必须涉及两个节点,问题就转化为了:如何分组配对,使得异或后的节点总价值尽可能大?
   – 异或操作是可逆的,因此每个节点最多只需要考虑异或一次。
   – 我们可以计算每个节点如果进行一次异或操作后的“收益”:diff[i] = (nums[i] ^ k) – nums[i]。

3. 贪心策略:
   – 首先计算所有节点不进行任何操作时的原始总价值。
   – 计算每个节点的收益 diff[i],并将其按降序排序。
   – 因为每次操作必须成对进行,所以我们每次从排序后的数组中取出最大的两个收益值相加。如果它们的和大于等于 0,说明这一对操作能带来正向收益,将其加入总价值;如果和小于 0,则停止操作,因为后续的收益只会更小。

Java 代码实现

import java.util.Arrays;

class Solution {
    public long maximumValueSum(int[] nums, int k, int[][] edges) {
        long ans = 0;
        int n = nums.length;
        int[] diff = new int[n];
        
        // 1. 计算原始总价值,并求出每个节点异或 k 后的收益差值
        for (int i = 0; i < n; i++) {
            ans += nums[i];
            diff[i] = (nums[i] ^ k) – nums[i];
        }
        
        // 2. 将收益差值按升序排序
        Arrays.sort(diff);
        
        // 3. 贪心配对:从最大的两个差值开始尝试配对
        // 只要两个差值之和 >= 0,就执行异或操作(累加收益)
        for (int i = n – 1; i > 0 && diff[i] + diff[i – 1] >= 0; i -= 2) {
            ans += diff[i] + diff[i – 1];
        }
        
        return ans;
    }
}

复杂度分析

– 时间复杂度:O(n log n)。其中 n 是节点数,主要耗时在对 diff 数组进行排序,后续的遍历操作仅需 O(n) 的时间。
– 空间复杂度:O(n)。主要用于存储 diff 差值数组。

 

赞(0)
未经允许不得转载:171主机测评 » 千问 LeetCode 3068. 最大节点价值之和 Java实现
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址