2497. Maximum Star Sum of a Graph
Problem Description
You are given an undirected graph with n
nodes numbered from 0
to n - 1
. Each node has a value given in the array vals
, where vals[i]
represents the value of node i
. The graph's edges are provided in a 2D array edges
, where each edges[i] = [ai, bi]
indicates an undirected edge between nodes ai
and bi
.
A star graph is a special subgraph where one central node connects to zero or more other nodes directly. In other words, it's a subset of edges from the original graph where all edges share exactly one common node (the center).
The star sum is calculated by adding up the values of all nodes in the star graph - this includes the center node's value plus the values of all nodes connected to it.
Your task is to find the maximum possible star sum when the star graph contains at most k
edges. This means you can choose any node as the center and connect it to up to k
of its neighbors (or fewer if it doesn't have k
neighbors).
For example, if a node with value 5 is the center and it connects to nodes with values 3, -2, and 7, and k = 2
, you could choose to include the edges to nodes with values 3 and 7 (skipping the negative value -2) to get a star sum of 5 + 3 + 7 = 15.
The goal is to return the maximum star sum possible across all possible choices of center nodes and their edge selections.
Intuition
To maximize the star sum, we need to think about what makes a star graph's sum as large as possible. Since every star graph has a center node whose value we must include, and then we can choose up to k
neighbors to connect to, the strategy becomes clear: for each potential center node, we want to greedily select its most valuable neighbors.
The key insight is that we should only include neighbors with positive values. Why? Because adding a neighbor with a negative value would decrease our total sum. Since we're allowed to use "at most" k
edges (not exactly k
), we can simply skip any negative-valued neighbors.
For each node that could serve as a center, we want to:
- Start with the node's own value (this is mandatory)
- Look at all its neighbors' values
- Only consider neighbors with positive values (adding negative values would hurt our sum)
- Sort these positive neighbor values in descending order
- Take the top
k
values (or fewer if there aren'tk
positive neighbors)
By trying every node as a potential center and applying this greedy strategy, we can find the maximum possible star sum. The greedy approach works here because once we fix a center, the problem becomes independent - we're simply choosing the k
largest positive values from the available neighbors, and there's no interaction between our choices that would require a more complex approach.
This leads us to preprocess the graph by creating adjacency lists that only store positive-valued neighbors for each node, sort these lists in descending order, and then for each node, calculate its potential star sum by taking its own value plus the sum of its top k
positive neighbors.
Learn more about Greedy, Graph, Sorting and Heap (Priority Queue) patterns.
Solution Approach
The implementation follows the greedy strategy we identified by building an adjacency list that only stores positive-valued neighbors for each node.
First, we create a graph representation using a defaultdict(list)
to store adjacency lists. As we process each edge [a, b]
, we make two key decisions:
- If
vals[b] > 0
, we addvals[b]
to nodea
's adjacency list (sinceb
would be a beneficial neighbor ifa
is the center) - If
vals[a] > 0
, we addvals[a]
to nodeb
's adjacency list (sincea
would be a beneficial neighbor ifb
is the center)
This preprocessing step filters out negative-valued neighbors immediately, saving us from considering them later.
Next, we sort each node's adjacency list in descending order using bs.sort(reverse=True)
. This ensures that when we select neighbors for a star graph, we can simply take the first k
elements to get the maximum possible contribution.
Finally, we calculate the maximum star sum by iterating through all nodes as potential centers. For each node i
with value v
:
- We compute its star sum as
v + sum(g[i][:k])
v
is the center node's value (which we must include)g[i][:k]
gives us the topk
positive neighbor values (or all of them if there are fewer thank
)- The slice
[:k]
automatically handles cases where a node has fewer thank
positive neighbors
The expression max(v + sum(g[i][:k]) for i, v in enumerate(vals))
efficiently finds the maximum star sum across all possible center choices. If a node has no positive neighbors, g[i]
will be an empty list, and sum(g[i][:k])
will be 0, so the star sum will just be the node's own value.
This approach has a time complexity of O(E + V log V)
where E
is the number of edges (for building the graph) and V
is the number of nodes (for sorting each adjacency list), and space complexity of O(E)
for storing the adjacency lists.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example to illustrate the solution approach.
Given:
n = 5
nodes (numbered 0 to 4)vals = [10, -5, 3, 8, -2]
(node values)edges = [[0,1], [0,2], [0,3], [1,4], [2,3]]
(connections)k = 2
(maximum edges in star graph)
Step 1: Build the filtered adjacency list
We process each edge and only add positive-valued neighbors:
-
Edge
[0,1]
:- Node 1 has value -5 (negative), so we don't add it to node 0's list
- Node 0 has value 10 (positive), so we add 10 to node 1's list
-
Edge
[0,2]
:- Node 2 has value 3 (positive), so we add 3 to node 0's list
- Node 0 has value 10 (positive), so we add 10 to node 2's list
-
Edge
[0,3]
:- Node 3 has value 8 (positive), so we add 8 to node 0's list
- Node 0 has value 10 (positive), so we add 10 to node 3's list
-
Edge
[1,4]
:- Node 4 has value -2 (negative), so we don't add it to node 1's list
- Node 1 has value -5 (negative), so we don't add it to node 4's list
-
Edge
[2,3]
:- Node 3 has value 8 (positive), so we add 8 to node 2's list
- Node 2 has value 3 (positive), so we add 3 to node 3's list
Resulting adjacency lists:
g[0] = [3, 8]
(positive neighbors of node 0)g[1] = [10]
(positive neighbors of node 1)g[2] = [10, 8]
(positive neighbors of node 2)g[3] = [10, 3]
(positive neighbors of node 3)g[4] = []
(no positive neighbors)
Step 2: Sort each adjacency list in descending order
g[0] = [8, 3]
(sorted)g[1] = [10]
(already sorted)g[2] = [10, 8]
(already sorted)g[3] = [10, 3]
(already sorted)g[4] = []
(empty)
Step 3: Calculate star sum for each potential center
For each node as center, take its value plus the sum of its top k=2 neighbors:
- Node 0 as center:
10 + sum([8, 3][:2]) = 10 + 8 + 3 = 21
- Node 1 as center:
-5 + sum([10][:2]) = -5 + 10 = 5
- Node 2 as center:
3 + sum([10, 8][:2]) = 3 + 10 + 8 = 21
- Node 3 as center:
8 + sum([10, 3][:2]) = 8 + 10 + 3 = 21
- Node 4 as center:
-2 + sum([][:2]) = -2 + 0 = -2
Step 4: Return the maximum star sum
The maximum star sum is 21, which can be achieved by choosing node 0, 2, or 3 as the center.
When node 0 is the center, we form a star with edges to nodes 2 and 3 (values 3 and 8), giving us 10 + 3 + 8 = 21. This demonstrates how the greedy approach of selecting the k most valuable positive neighbors maximizes the star sum.
Solution Implementation
1from collections import defaultdict
2from typing import List
3
4class Solution:
5 def maxStarSum(self, vals: List[int], edges: List[List[int]], k: int) -> int:
6 # Build adjacency list storing positive neighbor values for each node
7 graph = defaultdict(list)
8
9 # For each edge, add positive-valued neighbors to respective nodes
10 for node_a, node_b in edges:
11 # If node_b has positive value, add it to node_a's neighbor list
12 if vals[node_b] > 0:
13 graph[node_a].append(vals[node_b])
14 # If node_a has positive value, add it to node_b's neighbor list
15 if vals[node_a] > 0:
16 graph[node_b].append(vals[node_a])
17
18 # Sort each node's neighbor values in descending order
19 # This allows us to easily select the k largest positive neighbors
20 for neighbor_values in graph.values():
21 neighbor_values.sort(reverse=True)
22
23 # Calculate maximum star sum
24 # For each node as center: node value + sum of up to k best neighbors
25 max_sum = float('-inf')
26 for node_idx, node_val in enumerate(vals):
27 # Take at most k neighbors (already sorted in descending order)
28 star_sum = node_val + sum(graph[node_idx][:k])
29 max_sum = max(max_sum, star_sum)
30
31 return max_sum
32
1class Solution {
2 public int maxStarSum(int[] vals, int[][] edges, int k) {
3 int n = vals.length;
4
5 // Create adjacency list to store positive-valued neighbors for each node
6 List<Integer>[] adjacencyList = new List[n];
7 Arrays.setAll(adjacencyList, index -> new ArrayList<>());
8
9 // Build the graph by adding only positive-valued neighbors
10 for (int[] edge : edges) {
11 int nodeA = edge[0];
12 int nodeB = edge[1];
13
14 // If nodeB has positive value, add it to nodeA's neighbor list
15 if (vals[nodeB] > 0) {
16 adjacencyList[nodeA].add(vals[nodeB]);
17 }
18
19 // If nodeA has positive value, add it to nodeB's neighbor list
20 if (vals[nodeA] > 0) {
21 adjacencyList[nodeB].add(vals[nodeA]);
22 }
23 }
24
25 // Sort each node's neighbor values in descending order to prioritize higher values
26 for (List<Integer> neighbors : adjacencyList) {
27 Collections.sort(neighbors, (a, b) -> b - a);
28 }
29
30 // Find the maximum star sum across all nodes
31 int maxSum = Integer.MIN_VALUE;
32
33 for (int currentNode = 0; currentNode < n; currentNode++) {
34 // Start with the current node's value as the center of the star
35 int starSum = vals[currentNode];
36
37 // Add up to k of the highest positive neighbor values
38 int neighborsToAdd = Math.min(adjacencyList[currentNode].size(), k);
39 for (int j = 0; j < neighborsToAdd; j++) {
40 starSum += adjacencyList[currentNode].get(j);
41 }
42
43 // Update the maximum star sum found so far
44 maxSum = Math.max(maxSum, starSum);
45 }
46
47 return maxSum;
48 }
49}
50
1class Solution {
2public:
3 int maxStarSum(vector<int>& vals, vector<vector<int>>& edges, int k) {
4 int n = vals.size();
5
6 // Build adjacency list storing positive neighbor values only
7 // graph[i] will store positive values of nodes connected to node i
8 vector<vector<int>> graph(n);
9
10 for (auto& edge : edges) {
11 int nodeA = edge[0];
12 int nodeB = edge[1];
13
14 // Only add positive valued neighbors to maximize star sum
15 if (vals[nodeB] > 0) {
16 graph[nodeA].emplace_back(vals[nodeB]);
17 }
18 if (vals[nodeA] > 0) {
19 graph[nodeB].emplace_back(vals[nodeA]);
20 }
21 }
22
23 // Sort each node's neighbor values in descending order
24 // This allows us to greedily pick the k largest values
25 for (auto& neighbors : graph) {
26 sort(neighbors.rbegin(), neighbors.rend());
27 }
28
29 int maxSum = INT_MIN;
30
31 // Calculate star sum for each node as center
32 for (int center = 0; center < n; ++center) {
33 // Start with the center node's value
34 int starSum = vals[center];
35
36 // Add up to k of the largest positive neighbor values
37 int neighborsToAdd = min(static_cast<int>(graph[center].size()), k);
38 for (int j = 0; j < neighborsToAdd; ++j) {
39 starSum += graph[center][j];
40 }
41
42 // Update maximum star sum found
43 maxSum = max(maxSum, starSum);
44 }
45
46 return maxSum;
47 }
48};
49
1function maxStarSum(vals: number[], edges: number[][], k: number): number {
2 const n = vals.length;
3
4 // Build adjacency list storing positive neighbor values only
5 // graph[i] will store positive values of nodes connected to node i
6 const graph: number[][] = Array(n).fill(null).map(() => []);
7
8 // Process each edge and store positive-valued neighbors
9 for (const edge of edges) {
10 const nodeA = edge[0];
11 const nodeB = edge[1];
12
13 // Only add positive valued neighbors to maximize star sum
14 if (vals[nodeB] > 0) {
15 graph[nodeA].push(vals[nodeB]);
16 }
17 if (vals[nodeA] > 0) {
18 graph[nodeB].push(vals[nodeA]);
19 }
20 }
21
22 // Sort each node's neighbor values in descending order
23 // This allows us to greedily pick the k largest values
24 for (const neighbors of graph) {
25 neighbors.sort((a, b) => b - a);
26 }
27
28 let maxSum = Number.MIN_SAFE_INTEGER;
29
30 // Calculate star sum for each node as center
31 for (let center = 0; center < n; center++) {
32 // Start with the center node's value
33 let starSum = vals[center];
34
35 // Add up to k of the largest positive neighbor values
36 const neighborsToAdd = Math.min(graph[center].length, k);
37 for (let j = 0; j < neighborsToAdd; j++) {
38 starSum += graph[center][j];
39 }
40
41 // Update maximum star sum found
42 maxSum = Math.max(maxSum, starSum);
43 }
44
45 return maxSum;
46}
47
Time and Space Complexity
Time Complexity: O(E + V*log(V) + V*k)
where E
is the number of edges, V
is the number of vertices (nodes), and k
is the maximum number of edges allowed in a star graph.
- Building the adjacency list takes
O(E)
time as we iterate through all edges once - For each vertex that has neighbors, we sort its neighbor values. In the worst case, a vertex could be connected to all other
V-1
vertices, so sorting takesO(V*log(V))
time per vertex with neighbors - The total sorting complexity across all vertices is bounded by
O(E*log(V))
since the total number of neighbor entries across all vertices is at most2*E
- Finding the maximum star sum requires iterating through all
V
vertices and for each vertex, summing up tok
values from its sorted neighbor list, which takesO(V*k)
time
Space Complexity: O(E)
- The adjacency list
g
stores at most2*E
values (each edge contributes two entries in the worst case when both node values are positive) - The sorting is done in-place, so no additional space is required for sorting
- The space for storing the input is not counted as extra space
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Forgetting to Handle k = 0 Case
A critical edge case occurs when k = 0
, meaning the star graph cannot have any edges. In this scenario, the star graph consists of only a single node (the center) with no connections. The maximum star sum would simply be the maximum value among all nodes.
Why this happens: Developers often focus on the general case where k > 0 and overlook that k = 0 is a valid input according to the problem constraints.
The issue: The current solution actually handles this correctly because graph[node_idx][:0]
returns an empty list, and sum([])
returns 0. However, it's not immediately obvious that this edge case is covered, which can lead to confusion during code review or debugging.
2. Including Negative-Valued Neighbors When Node Has Fewer Than k Positive Neighbors
A common mistake is thinking that if a node has fewer than k
positive neighbors, you must include negative neighbors to reach exactly k
edges.
Example scenario:
- Node 0 has value 10
- Node 0's neighbors have values [5, 3, -2, -7]
- k = 3
Incorrect approach: Include values [5, 3, -2] to get exactly 3 edges, resulting in sum = 10 + 5 + 3 - 2 = 16
Correct approach: Only include positive values [5, 3], resulting in sum = 10 + 5 + 3 = 18
Why this happens: The problem states "at most k edges," but developers might misinterpret this as needing to use exactly k edges when possible.
3. Double-Counting the Center Node's Value
When building the adjacency list, a subtle bug can occur if you accidentally include the center node's value in its own adjacency list or count it twice when calculating the star sum.
Incorrect implementation example:
# Wrong: might add node's own value to its neighbor list for node_a, node_b in edges: graph[node_a].append(vals[node_a]) # Wrong! graph[node_b].append(vals[node_b]) # Wrong!
Solution: Always ensure that the adjacency list for a node contains only its neighbors' values, not its own value. The center's value should be added exactly once when calculating the star sum.
4. Not Considering Isolated Nodes
If a node has no edges in the input (isolated node), it won't appear in the edges array, but it's still a valid candidate for being a star center with 0 edges.
Why this matters: An isolated node with a high positive value could potentially be the answer, especially when all other nodes have negative values or form stars with lower sums.
Solution: The current implementation handles this correctly by iterating through all nodes via enumerate(vals)
rather than only considering nodes that appear in edges. This ensures isolated nodes are evaluated as potential star centers.
In a binary min heap, the minimum element can be found in:
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
https assets algo monster cover_photos graph svg Graph Fundamentals Tree with 0 cycle At this point you should be pretty familiar with trees A tree is a special kind of graph a connected acyclic cycle less graph A graph may contain cycle s and nodes could be disconnected A tree
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
Want a Structured Path to Master System Design Too? Donβt Miss This!