3462. Maximum Sum With at Most K Elements
Problem Description
You are given a 2D integer matrix grid
of size n x m
, an integer array limits
of length n
, and an integer k
. The task is to find the maximum sum of at most k
elements from the matrix grid
such that:
- The number of elements taken from the
i
th row ofgrid
does not exceedlimits[i]
.
Return the maximum sum.
Intuition
To solve this problem, we need to select elements across the matrix grid
such that their sum is maximized, while adhering to the limitations laid out by limits
and k
. The constraints imply that we cannot exceed taking more than limits[i]
elements from the i
th row, and overall, we can't take more than k
elements in total.
The intuition here is to leverage a greedy approach with the help of a priority queue (min-heap):
-
Iterate through each row of the matrix. For each row:
- Sort the elements to easily access the largest values.
- Choose the largest elements up to the
limit
specified for that row.
-
Utilize a min-heap to keep track of the largest
k
elements from the sorted selections across all rows:- Push each selected element into the min-heap.
- If the heap grows beyond size
k
, remove the smallest element. This ensures that the heap always contains the largest possible elements we've seen thus far.
-
Once all rows are processed, the sum of elements within the min-heap will yield the desired maximum sum, observing the constraints given by
limits
andk
.
By structuring the solution in this way, we ensure we're always prioritizing the largest elements for our sum while respecting the given constraints.
Learn more about Greedy, Sorting and Heap (Priority Queue) patterns.
Solution Approach
The provided solution uses a greedy approach combined with a priority queue (min-heap) to determine the maximum sum of selected elements.
-
Priority Queue (Min-Heap): This data structure will help maintain the largest
k
elements efficiently. The operation of pushing and popping from a heap enables us to continually keep track of the most valuable elements while discarding less useful ones. -
Algorithm Steps:
- Initialize an empty priority queue
pq
. - For each row in the
grid
, paired with its corresponding value fromlimits
:- Sort the row to bring larger numbers to one end, making it easy to select the largest values.
- Select elements: From the sorted row, take up to
limit
elements and push each into the priority queue:for nums, limit in zip(grid, limits): nums.sort() for _ in range(limit): heappush(pq, nums.pop()) if len(pq) > k: heappop(pq)
- Maintain size: Make sure the total number of elements in
pq
does not exceedk
. If it does, remove the smallest element (the top of the min-heap).
- Initialize an empty priority queue
-
Compute Maximum Sum: Once all rows are processed, sum all the elements in the priority queue. Since the queue contains only the largest possible selections of size
k
, this will be our maximum sum:return sum(pq)
This approach efficiently selects and sums the maximum possible elements while respecting the constraints on the number of elements selectable from each row and the total elements selected.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example to illustrate the solution approach:
Example Input:
grid = [[5, 3, 4], [8, 1], [6, 9, 2]]
limits = [2, 1, 1]
k = 3
Step-by-Step Approach:
-
Initialize the Priority Queue:
- Start with an empty min-heap
pq = []
.
- Start with an empty min-heap
-
Process Each Row:
-
Row 1:
[5, 3, 4]
with limit2
- Sort the row to get
[3, 4, 5]
. - Select the two largest values,
4
and5
:- Push
4
topq
:pq = [4]
- Push
5
topq
:pq = [4, 5]
- Push
- Sort the row to get
-
Row 2:
[8, 1]
with limit1
- Sort the row to get
[1, 8]
. - Select the single largest value,
8
:- Push
8
topq
:pq = [4, 5, 8]
- Push
- Sort the row to get
-
Row 3:
[6, 9, 2]
with limit1
- Sort the row to get
[2, 6, 9]
. - Select the single largest value,
9
:- Push
9
topq
:pq = [4, 5, 8, 9]
- The heap exceeds size
k
, so remove the smallest element,4
:pq = [5, 9, 8]
- Push
- Sort the row to get
-
-
Compute the Maximum Sum:
- The elements in the min-heap are
[5, 9, 8]
. - The maximum sum is the sum of these elements:
5 + 9 + 8 = 22
.
- The elements in the min-heap are
Thus, following the outlined strategy and constraints, the maximum sum we can achieve is 22
.
Solution Implementation
1from heapq import heappush, heappop
2from typing import List
3
4class Solution:
5 def maxSum(self, grid: List[List[int]], limits: List[int], k: int) -> int:
6 # Initialize a min-heap to store the largest k elements
7 min_heap = []
8
9 # Iterate over each pair of numbers list and corresponding limit
10 for nums, limit in zip(grid, limits):
11 # Sort the current list in ascending order
12 nums.sort()
13
14 # Push the largest 'limit' elements from 'nums' into the heap
15 for _ in range(limit):
16 # Push the largest element, and pop it from 'nums'
17 heappush(min_heap, nums.pop())
18
19 # Ensure the heap maintains only the largest k elements
20 if len(min_heap) > k:
21 heappop(min_heap)
22
23 # Return the sum of elements in the min-heap, which contains the largest k elements
24 return sum(min_heap)
25
1import java.util.*;
2
3class Solution {
4 public long maxSum(int[][] grid, int[] limits, int k) {
5 // Initialize a min-heap to keep track of the top 'k' largest numbers
6 PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
7 int numberOfRows = grid.length;
8
9 for (int i = 0; i < numberOfRows; ++i) {
10 int[] row = grid[i];
11 int limit = limits[i];
12
13 // Sort each row in ascending order
14 Arrays.sort(row);
15
16 // Add the 'limit' largest elements from the current row to the heap
17 for (int j = 0; j < limit; ++j) {
18 priorityQueue.offer(row[row.length - j - 1]);
19
20 // If the heap size exceeds 'k', remove the smallest element
21 if (priorityQueue.size() > k) {
22 priorityQueue.poll();
23 }
24 }
25 }
26
27 // Accumulate the top 'k' elements in the heap to calculate the maximum sum
28 long maxSum = 0;
29 for (int element : priorityQueue) {
30 maxSum += element;
31 }
32
33 return maxSum;
34 }
35}
36
1#include <vector>
2#include <queue>
3#include <algorithm> // For std::sort
4
5class Solution {
6public:
7 long long maxSum(std::vector<std::vector<int>>& grid, std::vector<int>& limits, int k) {
8 // Min-heap to maintain top k largest elements
9 std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;
10 int n = grid.size();
11
12 // Iterate over each row in the grid
13 for (int i = 0; i < n; ++i) {
14 std::vector<int> nums = grid[i];
15 int limit = limits[i];
16
17 // Sort the row in ascending order
18 std::sort(nums.begin(), nums.end());
19
20 // Push the largest 'limit' numbers onto the heap
21 for (int j = 0; j < limit; ++j) {
22 minHeap.push(nums[nums.size() - j - 1]);
23
24 // If the heap size exceeds k, remove the smallest element
25 if (minHeap.size() > k) {
26 minHeap.pop();
27 }
28 }
29 }
30
31 long long ans = 0;
32 // Sum up the largest k elements from the heap
33 while (!minHeap.empty()) {
34 ans += minHeap.top();
35 minHeap.pop();
36 }
37
38 return ans; // Return the maximum sum achievable
39 }
40};
41
1// Import the necessary module for a Priority Queue
2import { MinPriorityQueue } from '@datastructures-js/priority-queue';
3
4/**
5 * Function to calculate the maximum sum of elements from a 2D grid
6 * constrained by given limits and selecting only k elements in total.
7 *
8 * @param grid - A 2D grid (array of arrays) containing numbers
9 * @param limits - An array of numbers representing the limit for each row
10 * @param k - A number representing the maximum elements to consider for the sum
11 * @returns The maximum sum of selected elements
12 */
13function maxSum(grid: number[][], limits: number[], k: number): number {
14 // Create a Min-Priority Queue to keep track of the top k largest values
15 const pq = new MinPriorityQueue();
16
17 // Number of rows in the grid
18 const n = grid.length;
19
20 // Process each row of the grid
21 for (let i = 0; i < n; i++) {
22 const nums = grid[i]; // Current row
23 const limit = limits[i]; // Limit for the current row
24
25 // Sort the current row in ascending order
26 nums.sort((a, b) => a - b);
27
28 // Add the largest 'limit' number of elements from the sorted row to the priority queue
29 for (let j = 0; j < limit; j++) {
30 pq.enqueue(nums[nums.length - j - 1]); // Add the largest available number
31
32 // Ensure the priority queue does not have more than k elements
33 if (pq.size() > k) {
34 pq.dequeue(); // Remove the smallest element if size exceeds k
35 }
36 }
37 }
38
39 let ans = 0; // Variable to hold the sum of the top k elements
40
41 // Sum up the elements in the priority queue
42 while (!pq.isEmpty()) {
43 ans += pq.dequeue() as number;
44 }
45
46 // Return the final calculated maximum sum
47 return ans;
48}
49
Time and Space Complexity
The code iterates over each row of the grid
, which has n
rows and m
columns. For each row, the contents are sorted in O(m \log m)
. For each of the limit
elements in the row, the code performs a heappush
operation, which is O(\log k)
. If the size of pq
exceeds k
, a heappop
operation is also executed, which is O(\log k)
. Thus, for each row, the cumulative operations take O(m \log m + \text{limit} \times \log k)
.
Considering limit
can be up to m
, this implies the worst-case time complexity for a single row is O(m \log m + m \log k)
. Therefore, for all n
rows, the time complexity becomes O(n \times m \times (\log m + \log k))
.
The space complexity is dictated by the size of the heap pq
, which at most contains k
elements. Therefore, the space complexity is O(k)
.
Learn more about how to find time and space complexity quickly.
Which of these pictures shows the visit order of a depth-first search?
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
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
https algomonster s3 us east 2 amazonaws com cover_photos heap svg Priority Queue and Heap What is the relationship between priority queue and heap Priority Queue is an Abstract Data Type and Heap is the concrete data structure we use to implement a priority queue Priority Queue A priority queue
Want a Structured Path to Master System Design Too? Don’t Miss This!