Facebook Pixel

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 ith row of grid does not exceed limits[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 ith 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):

  1. 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.
  2. 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.
  3. 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 and k.

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.

  1. 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.

  2. Algorithm Steps:

    • Initialize an empty priority queue pq.
    • For each row in the grid, paired with its corresponding value from limits:
      • 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 exceed k. If it does, remove the smallest element (the top of the min-heap).
  3. 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 Evaluator

Example 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:

  1. Initialize the Priority Queue:

    • Start with an empty min-heap pq = [].
  2. Process Each Row:

    • Row 1: [5, 3, 4] with limit 2

      • Sort the row to get [3, 4, 5].
      • Select the two largest values, 4 and 5:
        • Push 4 to pq: pq = [4]
        • Push 5 to pq: pq = [4, 5]
    • Row 2: [8, 1] with limit 1

      • Sort the row to get [1, 8].
      • Select the single largest value, 8:
        • Push 8 to pq: pq = [4, 5, 8]
    • Row 3: [6, 9, 2] with limit 1

      • Sort the row to get [2, 6, 9].
      • Select the single largest value, 9:
        • Push 9 to pq: pq = [4, 5, 8, 9]
        • The heap exceeds size k, so remove the smallest element, 4: pq = [5, 9, 8]
  3. 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.

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.


Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:
Question 1 out of 10

Which of these pictures shows the visit order of a depth-first search?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!


Load More