leetcode
leetcode 2151 ~ 2200
图中最大星和

图中最大星和

难度:

标签:

题目描述

There is an undirected graph consisting of n nodes numbered from 0 to n - 1. You are given a 0-indexed integer array vals of length n where vals[i] denotes the value of the ith node.

You are also given a 2D integer array edges where edges[i] = [ai, bi] denotes that there exists an undirected edge connecting nodes ai and bi.

A star graph is a subgraph of the given graph having a center node containing 0 or more neighbors. In other words, it is a subset of edges of the given graph such that there exists a common node for all edges.

The image below shows star graphs with 3 and 4 neighbors respectively, centered at the blue node.

The star sum is the sum of the values of all the nodes present in the star graph.

Given an integer k, return the maximum star sum of a star graph containing at most k edges.

 

Example 1:

Input: vals = [1,2,3,4,10,-10,-20], edges = [[0,1],[1,2],[1,3],[3,4],[3,5],[3,6]], k = 2
Output: 16
Explanation: The above diagram represents the input graph.
The star graph with the maximum star sum is denoted by blue. It is centered at 3 and includes its neighbors 1 and 4.
It can be shown it is not possible to get a star graph with a sum greater than 16.

Example 2:

Input: vals = [-5], edges = [], k = 0
Output: -5
Explanation: There is only one possible star graph, which is node 0 itself.
Hence, we return -5.

 

Constraints:

  • n == vals.length
  • 1 <= n <= 105
  • -104 <= vals[i] <= 104
  • 0 <= edges.length <= min(n * (n - 1) / 2, 105)
  • edges[i].length == 2
  • 0 <= ai, bi <= n - 1
  • ai != bi
  • 0 <= k <= n - 1

代码结果

运行时间: 180 ms, 内存: 50.8 MB


/*
 * 思路:
 * 1. 使用一个邻接表来表示图。
 * 2. 遍历每个节点,计算以该节点为中心节点的最大星和。
 * 3. 对于每个节点,首先获取它的所有邻居节点。
 * 4. 对这些邻居节点的值进行排序,选择值最大的k个邻居,计算它们的和。
 * 5. 将中心节点的值与选择的邻居节点的值之和计算出来即为星和。
 * 6. 返回所有星和中的最大值。
 */

import java.util.*;
import java.util.stream.Collectors;

public class MaxStarSumStream {
    public int maxStarSum(int[] vals, int[][] edges, int k) {
        int n = vals.length;
        List<List<Integer>> graph = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            graph.add(new ArrayList<>());
        }
        for (int[] edge : edges) {
            graph.get(edge[0]).add(edge[1]);
            graph.get(edge[1]).add(edge[0]);
        }

        return Arrays.stream(vals).map(i -> {
            List<Integer> neighbors = graph.get(i);
            return neighbors.stream()
                .map(neighbor -> vals[neighbor])
                .sorted(Collections.reverseOrder())
                .limit(k)
                .reduce(vals[i], Integer::sum);
        }).max(Integer::compareTo).orElse(Integer.MIN_VALUE);
    }
}

解释

方法:

该题解主要采用了贪心策略和优先队列(最小堆)来解决问题。首先,为每个节点维护一个优先队列(最小堆),用来存储该节点的所有邻居节点的值,但只保留值最大的k个邻居。这是因为我们想要最大化星和,所以只保留最大的k个邻居值。当遍历每条边时,我们将节点值为正的邻居节点的值添加到对应的优先队列中。如果队列的长度超过k,则移除最小的元素,确保队列中只保留k个最大的值。在构建完所有节点的优先队列后,我们计算每个节点作为中心,其星和的最大值,即节点本身的值加上其优先队列中所有值的和,最后返回所有节点的最大星和。

时间复杂度:

O(m * log k + n * k)

空间复杂度:

O(n * k)

代码细节讲解

🦆
在确定使用优先队列(最小堆)来维持每个节点的k个最大邻居值时,如何处理邻居节点值为0或负数的情况?
在此题解中,对于邻居节点值为0或负数的情况,我们选择不将这些值加入优先队列(最小堆)。这是因为我们的目标是最大化每个节点的星和,而星和的计算只考虑正值对总和的贡献。将值为0或负数的邻居加入堆中不仅无助于提升星和,反而可能占据堆中的有限空间(k个位置),导致不能保留更多的正值邻居,从而降低可能的最大星和。
🦆
为什么在处理每个节点的星和时,只考虑邻居节点的值而忽略邻居节点的邻居情况?这是否会影响结果的正确性?
这种处理方式基于题目定义的星和的计算方法,即一个节点的星和是该节点值和其最大的k个邻居值的总和。这里的关键是只考虑直接邻居的值对星和的贡献,而非邻居的邻居。这种定义下的计算方法是准确的,不会影响结果的正确性。忽略邻居的邻居情况是因为题目仅要求计算直接邻居的影响。
🦆
在计算最大星和时,如果某个节点的邻居数量少于k个,这种情况下是如何处理的?
如果某个节点的邻居数量少于k个,我们仍然会把这些邻居(只要它们的值为正)的值添加到该节点的优先队列中,但这个队列中的元素数量将少于k个。在计算该节点的星和时,我们只将队列中存在的邻居值求和,加上节点本身的值。这意味着,即使邻居数量不足k个,我们也能正确处理并计算出该节点的星和。
🦆
题解提到的贪心策略在选择保留k个最大邻居时是否有可能忽略某些重要的算法优化,例如在特定条件下提前确定星和的最大值?
贪心策略在选择保留k个最大邻居时主要目的是简化问题并尽可能地寻找局部最优解。这种策略可能确实忽略了一些可能的全局优化,比如考虑特定的图结构或特殊情况下的优化策略。然而,对于大多数情况,贪心策略提供了一个效率高且实现简单的解决方案。对于能否在特定条件下提前确定星和的最大值,这取决于具体问题的限制和附加条件,可能需要更复杂的算法或数据结构来实现更优的解决方案。

相关问题