Problem Overview
LeetCode 2542 Maximum Subsequence Score gives you two integer arrays nums1 and nums2 of equal length n, and an integer k. Your task is to choose exactly k indices from the array and compute a score based on those choices.
The score is defined as the sum of nums1 at the chosen indices multiplied by the minimum value of nums2 at those same indices. Formally: score = (sum of nums1[i] for chosen i) * (min of nums2[i] for chosen i). You want to maximize this score.
At first glance it looks like a two-dimensional optimization — you have to balance the sum of nums1 values against how low the minimum of nums2 values drops. A brute-force approach checking every combination of k indices would be O(n choose k), which is far too slow.
- Given: nums1, nums2 (equal length n), and integer k
- Choose exactly k indices from [0, n-1]
- Score = sum(nums1[chosen indices]) * min(nums2[chosen indices])
- Goal: maximize the score
- Constraint: 1 <= k <= n <= 100,000 — brute force is infeasible
Sort + Heap Strategy
The key insight is to fix the minimum of nums2. If we sort all index pairs by nums2 in descending order, then as we scan left to right, each new element we process has the current smallest nums2 value seen so far. That element becomes the definitive minimum for any group we form using it.
With the minimum of nums2 fixed at each step, we want to maximize the sum of nums1 over k elements. We maintain a min-heap of size k that always holds the k largest nums1 values seen so far. The heap lets us efficiently evict the smallest nums1 value when we add a new candidate and the heap exceeds size k.
This reduces the problem to a single O(n log n) sort followed by O(n log k) heap operations — a dramatic improvement over brute force. The score at each step is the current heap sum multiplied by the current nums2 value, and we track the running maximum.
Core Insight
By sorting nums2 descending, each new element we consider becomes the new minimum of nums2 for any group using it. The min-heap then ensures we always hold the k largest nums1 values seen so far — maximizing the sum half of the score.
Algorithm
The algorithm pairs nums1[i] and nums2[i], then sorts the pairs by nums2 descending. It uses a min-heap to track the k largest nums1 values seen so far, along with a running sum of those values.
For the first k elements, we push each nums1 value into the heap and add it to the running sum. No score is recorded yet because we need exactly k elements. Starting from the (k+1)th element onward, we push the new nums1 value, add it to the sum, then pop the heap minimum and subtract it — maintaining the heap at exactly size k.
After each operation from index k-1 onward, we compute score = running_sum * current_nums2 and update the global maximum. The final answer is the maximum score observed across all positions.
- 1Zip nums1 and nums2 into pairs, sort by nums2 descending
- 2Initialize a min-heap, a running sum = 0, and max_score = 0
- 3For the first k elements: push nums1 value onto heap, add to sum
- 4Compute initial score after exactly k elements: score = sum * nums2[k-1]
- 5For each remaining element: push nums1 value, add to sum, pop heap min, subtract from sum
- 6After each push/pop, update max_score = max(max_score, sum * current nums2)
- 7Return max_score
Why This Guarantees Optimality
The sort step ensures that when we consider position i, nums2[i] is the smallest nums2 value among all pairs we have processed (indices 0 through i in sorted order). Any group of k indices that includes position i must use nums2[i] as its minimum — no way around it, because all earlier indices have larger nums2 values.
Given that the minimum is fixed at nums2[i], the only lever we control is the sum of nums1. A min-heap of size k gives us the k largest nums1 values seen so far in O(log k) time per operation. Because we try every possible nums2 minimum (every position in the sorted order), we exhaustively cover all candidate optimal subsets.
No valid k-element subset is ever skipped. Every subset has some element with the smallest nums2 — that element determines which iteration of our loop computes the score for that subset. The heap guarantees the best possible nums1 sum for that minimum, so the algorithm considers the best achievable score for every candidate minimum value.
Pattern Recognition
The sort-by-min-then-greedily-maximize-sum pattern appears throughout competitive programming. Whenever the score involves a product of a sum and a minimum (or maximum), sorting to fix one factor and using a heap to optimize the other is the standard O(n log n) approach.
Walk-Through Example
Consider nums1 = [1, 3, 3, 2], nums2 = [2, 1, 3, 4], k = 3. After pairing and sorting by nums2 descending we get: [(2, 4), (3, 3), (1, 2), (3, 1)]. The first value in each pair is nums1, the second is nums2.
Processing the first k = 3 elements: add 2 (sum = 2), add 3 (sum = 5), add 1 (sum = 6). After the third element, score = 6 * 2 = 12. The heap contains [1, 2, 3] (min-heap).
Next element is (3, 1). Push 3 onto heap → heap = [1, 2, 3, 3], sum = 9. Pop min (1) → heap = [2, 3, 3], sum = 8. Score = 8 * 1 = 8. Maximum remains 12. The final answer is 12.
- 1Pairs sorted by nums2 desc: [(2,4), (3,3), (1,2), (3,1)]
- 2i=0: push 2 → heap=[2], sum=2
- 3i=1: push 3 → heap=[2,3], sum=5
- 4i=2: push 1 → heap=[1,2,3], sum=6; score = 6 * 2 = 12; max_score = 12
- 5i=3: push 3 → heap=[1,2,3,3], sum=9; pop 1 → heap=[2,3,3], sum=8; score = 8 * 1 = 8
- 6max_score unchanged at 12 — final answer is 12
Code Walkthrough — Python and Java
In Python, zip(nums1, nums2) creates the pairs, sorted(..., key=lambda x: -x[1]) sorts by nums2 descending, and heapq provides the min-heap. The total time complexity is O(n log n) for the sort plus O(n log k) for n heap operations each costing O(log k). Space complexity is O(k) for the heap.
In Java, you create a 2D array or list of pairs, sort with a lambda comparator on the nums2 column descending, and use a PriorityQueue as the min-heap. The logic is identical — push, check size, pop if over k, update max score.
Both implementations stay well within the constraints for n = 100,000. The sort dominates at O(n log n). The heap operations are O(n log k) which is at most O(n log n) in the worst case when k = n, but typically much faster for small k.
Off-by-One Pitfall
Start tracking max score only after pushing k elements — the first k-1 iterations do not yet form a valid group of exactly k indices. In the loop, compute the candidate score only when the heap already contains k elements (i.e., after the k-th push and before or without any pop for the first k).