Maximum Subsequence Score
You are given two arrays paired by index. Choose k indices to maximize (sum of the chosen nums1) × (min of the chosen nums2). The min depends on which indices you pick, so the two factors interact — a larger sum often forces a smaller min. This page works through why sorting once and sweeping with a heap solves it in O(n log n).
One sort, one heap
The whole solution is two moves. Say them cleanly and stop:
nums2 descending. Sweep left to right, pushing each nums1 into a min-heap; if the heap passes size k, pop the smallest. Whenever it holds exactly k, the current element's nums2 is the group's minimum, so heap_sum × nums2 is a candidate answer. Keep the max — O(n log n)."That's it. The rest of this page is why those two moves are correct: why a descending sort, why the current element is always a legitimate minimum, and why a size-k heap is exactly the right bookkeeping.
The objective: sum × min
Before optimizing, look at how the score behaves. With four items and k = 3 there are only four selections — enumerate them and notice that the best one is neither the largest sum nor the largest single min. The two factors trade off.
Note: dropping index 1 (its nums2 = 1) shrank the sum yet gave the best score, because it raised the min from 1 to 2. The score is governed by whichever chosen element has the smallest nums2. That element has a name.
Every selection has a bottleneck
The minimum isn't chosen independently — it's pinned to one chosen element: the one with the smallest nums2. Call it the bottleneck. If we decide the bottleneck first, every other pick simply has to sit at or above it.
nums2, largest first. Now "pick a bottleneck and only allow elements at or above it" becomes "stand on an element and only use the ones to its left." The minimum is now just a position in the sorted order, not a circular dependency.Fix the minimum, then maximize the sum
Instead of searching over selections, search over the value of the minimum. There are only n possible minimums (one per element). For each, the best selection is clear: take the top-k nums1 among the elements whose nums2 is at least that minimum, and multiply by the minimum. Try every minimum and keep the largest result.
One sweep covers every minimum
Trying each minimum and recomputing the top-k from scratch is wasteful. But scanning minimums from high to low is just walking the sorted-descending list — and "the top-k nums1 seen so far" is exactly what a size-k min-heap maintains incrementally. The whole scan is one pass.
Why the heap pops the smallest: once you hold k+1 candidates, the one with the least nums1 can never belong to an optimal sum at any lower minimum either — so evicting it permanently is safe. That greedy step is what keeps the sweep correct.
Why the current element is a valid minimum
One detail deserves a clean answer. When we read sum × nums2[i], is nums2[i] really the minimum of the chosen k? Because we sorted descending, every element in the heap has nums2 ≥ nums2[i]. So the real minimum of that group is at least nums2[i] — meaning our candidate is never an overestimate.
Where this approach shows up again
The general rule: when an objective couples two factors and one of them is a min or max over the chosen set, sort by that factor so it becomes predictable, then sweep while a heap manages the other. The min stops being circular once you fix the order in which you meet the elements.
The traps that break naive code
Five things an interviewer will poke at — each one falls out of getting the sort direction and the heap size right.
sum × n2 with fewer than k in the heap counts a phantom selection.long. Ruby's integers are unbounded, but say it out loud.The interview cheat-sheet
nums1 into a min-heap; if it exceeds k, pop the smallest and subtract. When the heap holds exactly k, sum × current nums2 is a candidate. O(n log n).sum × current_nums2 is never an overestimate — every element left in the heap has nums2 ≥ current, so the true score of that group is ≥ what you recorded. You can only under-count, and the real optimum still gets hit exactly when its bottleneck is the cursor.max(nums1·nums2).sum × current nums2 at every step. One sort, one sweep, O(n log n)."