Maximum Score of a Node Sequence
HardPrompt
There is an undirected graph with n nodes, numbered from 0 to n - 1.
You are given a 0-indexed integer array scores of length n where scores[i] denotes the score of node i. 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 node sequence is valid if it meets the following conditions:
- There is an edge connecting every pair of adjacent nodes in the sequence.
- No node appears more than once in the sequence.
The score of a node sequence is defined as the sum of the scores of the nodes in the sequence.
Return the maximum score of a valid node sequence with a length of 4. If no such sequence exists, return -1.
Example 1:
Input: scores = [5,2,9,8,4], edges = [[0,1],[1,2],[2,3],[0,2],[1,3],[2,4]]
Output: 24
Explanation: The figure above shows the graph and the chosen node sequence [0,1,2,3].
The score of the node sequence is 5 + 2 + 9 + 8 = 24.
It can be shown that no other node sequence has a score of more than 24.
Note that the sequences [3,1,2,0] and [1,0,2,3] are also valid and have a score of 24.
The sequence [0,3,2,4] is not valid since no edge connects nodes 0 and 3.Example 2:
Input: scores = [9,20,6,4,11,12], edges = [[0,3],[5,3],[2,4],[1,3]]
Output: -1
Explanation: The figure above shows the graph.
There are no valid node sequences of length 4, so we return -1.
Constraints:
n == scores.length4 <= n <= 5 * 1041 <= scores[i] <= 1080 <= edges.length <= 5 * 104edges[i].length == 20 <= ai, bi <= n - 1ai != bi- There are no duplicate edges.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach considers every edge in the graph as the central edge of a potential 4-node sequence. For each edge (u, v), it exhaustively searches through all neighbors of u and v to find the other two nodes that complete the sequence and maximize the score.
Algorithm
-
- Construct an adjacency list
adjfor the graph.
- Construct an adjacency list
-
- Initialize
maxScore = -1.
- Initialize
-
- For each edge
(u, v)in the inputedgesarray:
- For each edge
-
- For each neighbor
aofu:
- For each neighbor
-
-
If `a` is the same as `v`, continue to the next neighbor.
-
-
-
For each neighbor `d` of `v`:
-
-
-
If `d` is the same as `u` or `a`, continue to the next neighbor.
-
-
-
Calculate `currentScore = scores[a] + scores[u] + scores[v] + scores[d]`.
-
-
-
Update `maxScore = max(maxScore, currentScore)`.
-
-
- Return
maxScore.
- Return
Walkthrough
First, we build an adjacency list representation of the graph from the given edges. We initialize a variable maxScore to -1. We then iterate through every edge (u, v) in the input edges array. These two nodes will form the middle part of our 4-node sequence a-u-v-d. For each edge (u, v), we need to find two other nodes: a, a neighbor of u, and d, a neighbor of v. The four nodes a, u, v, d must all be distinct. To do this, we use nested loops. The outer loop iterates through all neighbors of u (let's call a neighbor a). The inner loop iterates through all neighbors of v (let's call a neighbor d). Inside the inner loop, we check if the four nodes form a valid sequence of distinct nodes: a != v, d != u, and a != d. If they are distinct, we calculate the total score: scores[a] + scores[u] + scores[v] + scores[d]. We update maxScore with this score if it's higher than the current maxScore. After checking all edges and all their neighbor combinations, maxScore will hold the result. If no such sequence of length 4 is found, maxScore remains -1.
import java.util.*; class Solution { public int maximumScore(int[] scores, int[][] edges) { int n = scores.length; List<Integer>[] adj = new ArrayList[n]; for (int i = 0; i < n; i++) { adj[i] = new ArrayList<>(); } for (int[] edge : edges) { adj[edge[0]].add(edge[1]); adj[edge[1]].add(edge[0]); } long maxScore = -1; for (int[] edge : edges) { int u = edge[0]; int v = edge[1]; for (int neighborU : adj[u]) { if (neighborU == v) continue; for (int neighborV : adj[v]) { if (neighborV == u || neighborV == neighborU) continue; long currentScore = (long) scores[u] + scores[v] + scores[neighborU] + scores[neighborV]; maxScore = Math.max(maxScore, currentScore); } } } return (int) maxScore; }}Complexity
Time
O(sum_{(u,v) in E} (deg(u) * deg(v))). In the worst case, where `deg` is the degree of a node, this can be `O(E * d_max^2)`, where `d_max` is the maximum degree. This can be too slow for the given constraints.
Space
O(n + E) for storing the adjacency list, where `n` is the number of nodes and `E` is the number of edges.
Trade-offs
Pros
Conceptually simpler than the optimized approach.
Correctly finds the maximum score.
Cons
Inefficient time complexity, likely to time out on large test cases, especially for graphs with nodes of high degree.
This approach significantly optimizes the search for the two outer nodes of the sequence. It's based on the key insight that for any central edge (u, v), the optimal outer nodes a (neighbor of u) and d (neighbor of v) must be among the highest-scoring neighbors of u and v. Specifically, we only need to consider the top 3 neighbors with the highest scores for each node.
Algorithm
-
- Create an adjacency list
adjwhereadj[i]stores pairs of(score, neighbor_id)for each neighbor of nodei.
- Create an adjacency list
-
- For each node
ifrom0ton-1:
- For each node
-
- Sort
adj[i]in descending order based on scores.
- Sort
-
- Trim
adj[i]to keep only the top 3 neighbors.
- Trim
-
- Initialize
maxScore = -1.
- Initialize
-
- For each edge
(u, v)inedges:
- For each edge
-
- For each top neighbor
aofuin its trimmed list:
- For each top neighbor
-
-
For each top neighbor `d` of `v` in its trimmed list:
-
-
-
If `a`, `u`, `v`, `d` are all distinct (i.e., `a != v`, `d != u`, `a != d`):
-
-
-
Calculate `currentScore = scores[u] + scores[v] + scores[a] + scores[d]`.
-
-
-
Update `maxScore = max(maxScore, currentScore)`.
-
-
- Return
maxScore.
- Return
Walkthrough
The core idea is to iterate through each edge (u, v) as the middle part of the sequence a-u-v-d. To maximize the total score, we need to pick neighbors a and d with the highest possible scores. A crucial observation is that for any optimal sequence a*-u-v-d*, the node a* must be one of the top-scoring neighbors of u. If a* wasn't, say, in the top 3, there would be at least three other neighbors of u with scores greater than or equal to scores[a*]. At most two of these could be v or d*, leaving at least one high-scoring neighbor that could replace a* to yield an equal or better score. The same logic applies to d* and v. Therefore, we only need to check combinations from the top 3 neighbors of u and v.
The algorithm proceeds as follows:
- First, we build an adjacency list where for each node, we store its neighbors paired with their scores.
- For each node, we sort its neighbors in descending order based on their scores.
- We then trim each neighbor list to keep only the top 3. This pre-computation step is key to the efficiency.
- We initialize
maxScoreto -1. - We iterate through each edge
(u, v)in the graph. - For each edge, we perform a small, constant-time search. We iterate through the (at most 3) pre-computed top neighbors of
u(let's call onea) and the (at most 3) top neighbors ofv(let's call oned). This results in at most3 * 3 = 9checks per edge. - In each check, we ensure the four nodes
a, u, v, dare distinct. - If they are, we calculate the sum of their scores and update
maxScore. - Finally, we return
maxScore.
import java.util.*; class Solution { public int maximumScore(int[] scores, int[][] edges) { int n = scores.length; // Store neighbors as pairs of (score, node_id) List<int[]>[] adj = new ArrayList[n]; for (int i = 0; i < n; i++) { adj[i] = new ArrayList<>(); } for (int[] edge : edges) { int u = edge[0]; int v = edge[1]; adj[u].add(new int[]{scores[v], v}); adj[v].add(new int[]{scores[u], u}); } // Sort neighbors by score in descending order and keep top 3 for (int i = 0; i < n; i++) { Collections.sort(adj[i], (a, b) -> b[0] - a[0]); if (adj[i].size() > 3) { adj[i] = adj[i].subList(0, 3); } } long maxScore = -1; // Iterate through each middle edge (u, v) for (int[] edge : edges) { int u = edge[0]; int v = edge[1]; // Iterate through top neighbors of u and v for (int[] neighborU : adj[u]) { int a = neighborU[1]; for (int[] neighborV : adj[v]) { int d = neighborV[1]; // Check for distinct nodes if (a != v && d != u && a != d) { long currentScore = (long) scores[u] + scores[v] + scores[a] + scores[d]; maxScore = Math.max(maxScore, currentScore); } } } } return (int) maxScore; }}Complexity
Time
O(E * log(d_max) + E). The dominant part is sorting the adjacency lists for all nodes, which is bounded by `O(E * log n)`. The main loop runs in `O(E)` time since the inner loops are constant time (at most 3*3=9). So, the total time is `O(E * log n)`.
Space
O(n + E) to build the initial adjacency list. The trimmed list takes O(n) space. So, the total space is O(n + E).
Trade-offs
Pros
Highly efficient, with a time complexity that handles the given constraints easily.
The pre-computation step of sorting and trimming neighbors drastically reduces the search space.
Cons
Slightly more complex to implement due to the pre-processing step.
Requires careful reasoning to prove that considering only the top 3 neighbors is sufficient.
Solutions
Solution
class Solution {public int maximumScore(int[] scores, int[][] edges) { int n = scores.length; List<Integer>[] g = new List[n]; Arrays.setAll(g, k->new ArrayList<>()); for (int[] e : edges) { int a = e[0], b = e[1]; g[a].add(b); g[b].add(a); } for (int i = 0; i < n; ++i) { g[i].sort((a, b)->scores[b] - scores[a]); g[i] = g[i].subList(0, Math.min(3, g[i].size())); } int ans = -1; for (int[] e : edges) { int a = e[0], b = e[1]; for (int c : g[a]) { for (int d : g[b]) { if (c != b && c != d && a != d) { int t = scores[a] + scores[b] + scores[c] + scores[d]; ans = Math.max(ans, t); } } } } return ans; }}class Solution: def maximumScore(self, scores: List[int], edges: List[List[int]]) -> int: g = defaultdict(list) for a, b in edges: g[a]. append(b) g[b]. append(a) for k in g . keys(): g[k] = nlargest(3, g[k], key=lambda x: scores[x]) ans = - 1 for a, b in edges: for c in g[a]: for d in g[b]: if b != c != d != a: t = scores[a] + scores[b] + scores[c] + scores[d] ans = max(ans, t) return ansVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.