HomeLeetcode363. Max Sum of Rectangle No Larger Than K - Leetcode Solutions

363. Max Sum of Rectangle No Larger Than K – Leetcode Solutions

Description

Given an m x n matrix matrix and an integer k, return the max sum of a rectangle in the matrix such that its sum is no larger than k.

It is guaranteed that there will be a rectangle with a sum no larger than k.

Examples:

Example 1:

Input: matrix = [[1,0,1],[0,-2,3]], k = 2
Output: 2
Explanation: Because the sum of the blue rectangle [[0, 1], [-2, 3]] is 2, and 2 is the max number no larger than k (k = 2).

Example 2:

Input: matrix = [[2,2,-1]], k = 3
Output: 3

Solution in Python

To solve the problem of finding the maximum sum of a rectangle within a 2D matrix such that the sum does not exceed a given integer k, we can break down the problem as follows:

Approach:

This problem is a variation of the maximum subarray sum problem, but extended to two dimensions (rectangles within a matrix). The challenge is not just finding the rectangle with the maximum sum, but ensuring that the sum is no larger than k.

Key Insights:

  1. Submatrix Sum Calculation: We need to efficiently calculate the sum of all possible submatrices. A brute-force approach that computes the sum of every possible rectangle would be too slow (O(m² * n²) for all submatrices).
  2. Kadane’s Algorithm: A well-known algorithm for solving the 1D maximum subarray problem can be adapted to help solve this problem. Kadane’s algorithm can be applied to each pair of rows, reducing the problem to 1D for each submatrix.
  3. Bounding the Sum with k: The tricky part is ensuring that the submatrix sum is less than or equal to k. To achieve this efficiently, we can use a prefix sum and a sorted data structure (such as a SortedList) to find the sum of a subarray that is as close to k as possible without exceeding it.

Detailed Steps:

  1. Iterating over row pairs: Consider submatrices that span between pairs of rows. For each pair of rows, the problem is reduced to finding a subarray sum (in 1D) that does not exceed k.
  2. Using a prefix sum array: As we traverse each pair of rows, compute the prefix sum of the columns, and check if there’s a valid subarray whose sum is no larger than k.
  3. Binary search for valid subarrays: To find the subarray sum efficiently, maintain a sorted list of prefix sums, and use binary search to quickly find a prefix sum that satisfies the condition.
Python
class Solution:
    def maxSumSubmatrix(self, matrix: List[List[int]], k: int) -> int:
        # Get the dimensions of the matrix
        m, n = len(matrix), len(matrix[0])
        # Initialize the result variable to a very small number
        max_sum = float('-inf')
        
        # Iterate over all pairs of row ranges (i to j)
        for left in range(n):
            # Initialize a 1D array to store the row sums between two columns
            row_sums = [0] * m
            
            for right in range(left, n):
                # Update the row_sums array by adding elements from the current column (right)
                for i in range(m):
                    row_sums[i] += matrix[i][right]
                
                # Now we have a 1D problem: Find the maximum sum of any subarray in row_sums that is <= k
                # We use a sorted list of prefix sums to do this efficiently
                prefix_sums = [0]
                current_sum = 0
                
                for sum_value in row_sums:
                    # Update the current prefix sum
                    current_sum += sum_value
                    # We want to find the largest prefix sum such that (current_sum - prefix_sum) <= k
                    # Hence, we need to find the smallest prefix_sum >= current_sum - k
                    target = current_sum - k
                    idx = bisect_left(prefix_sums, target)
                    
                    if idx < len(prefix_sums):
                        max_sum = max(max_sum, current_sum - prefix_sums[idx])
                    
                    # Insert the current prefix_sum into the sorted list
                    insort(prefix_sums, current_sum)
        
        return max_sum

Explanation of the Code:

  1. Prefix Sums: The key idea is to use prefix sums to compute the sum of submatrices more efficiently. By summing up elements between two columns, we reduce the problem to a 1D array, and then use a sorted list of prefix sums to find the subarray with the maximum sum less than or equal to k.
  2. Outer Loops:
    • The outer loop iterates over all possible pairs of columns (left and right).
    • For each column pair, we maintain an array row_sums, where each element represents the sum of elements between the left and right columns for a specific row.
  3. Prefix Sum and Binary Search:
    • For each subarray (represented by row_sums), we calculate the cumulative sum (i.e., prefix sum) as we iterate through the rows.
    • We use binary search (bisect_left) to find the smallest prefix sum that allows the subarray sum to remain below or equal to k.
    • We keep track of the maximum valid subarray sum in max_sum.
  4. Handling Edge Cases:
    • If the matrix has only one element or only one row/column, the algorithm will still work correctly due to the way it reduces the problem to 1D for each pair of columns.

Solution in C++

C++
class Solution {
public:
    int maxSumSubmatrix(vector<vector<int>>& matrix, int k) {
        int rows = matrix.size();         // number of rows in the matrix
        int cols = matrix[0].size();      // number of columns in the matrix
        int maxSum = INT_MIN;             // initialize maximum sum to smallest possible integer

        // Iterate over all column pairs
        for (int left = 0; left < cols; ++left) {
            // Initialize an array to store the sum of elements in each row between two column pairs
            vector<int> rowSum(rows, 0);

            // Extend the right boundary of the rectangle
            for (int right = left; right < cols; ++right) {
                // Update rowSum to include the elements from the new right column
                for (int i = 0; i < rows; ++i) {
                    rowSum[i] += matrix[i][right];
                }

                // Now find the maximum subarray sum no larger than k for this rowSum array
                maxSum = max(maxSum, findMaxSubarraySum(rowSum, k));
            }
        }

        return maxSum;
    }

private:
    // Helper function to find the maximum subarray sum no larger than k
    int findMaxSubarraySum(vector<int>& arr, int k) {
        int currentSum = 0;
        int maxSum = INT_MIN;

        // Use a set to store the prefix sums
        set<int> prefixSums;
        prefixSums.insert(0);  // Add 0 as the initial prefix sum for comparison

        for (int sum : arr) {
            currentSum += sum;

            // Find the smallest prefix sum >= currentSum - k
            auto it = prefixSums.lower_bound(currentSum - k);
            if (it != prefixSums.end()) {
                // Update maxSum if a valid subarray sum is found
                maxSum = max(maxSum, currentSum - *it);
            }

            // Insert the current prefix sum into the set
            prefixSums.insert(currentSum);
        }

        return maxSum;
    }
};

Solution in Javascript

JavaScript
var maxSumSubmatrix = function(matrix, k) {
    // Function to find the maximum sum subarray in a 1D array that is no larger than k
    const maxSumNoLargerThanK = (arr, k) => {
        let maxSum = -Infinity;
        let currSum = 0;
        let sumSet = [0]; // Stores prefix sums
        
        for (let sum of arr) {
            currSum += sum;
            // Find the smallest prefix sum such that currSum - prefix <= k
            let left = binarySearch(sumSet, currSum - k);
            if (left !== null) {
                maxSum = Math.max(maxSum, currSum - sumSet[left]);
            }
            // Insert current prefix sum in sorted order
            insertInOrder(sumSet, currSum);
        }
        return maxSum;
    };

    // Binary search to find the first element greater than or equal to the target
    const binarySearch = (arr, target) => {
        let left = 0, right = arr.length;
        while (left < right) {
            let mid = Math.floor((left + right) / 2);
            if (arr[mid] >= target) right = mid;
            else left = mid + 1;
        }
        return left < arr.length ? left : null;
    };

    // Insert element into sorted array
    const insertInOrder = (arr, num) => {
        let left = 0, right = arr.length;
        while (left < right) {
            let mid = Math.floor((left + right) / 2);
            if (arr[mid] < num) left = mid + 1;
            else right = mid;
        }
        arr.splice(left, 0, num);
    };

    let maxResult = -Infinity;
    let rows = matrix.length, cols = matrix[0].length;

    // Iterate through all pairs of rows
    for (let leftRow = 0; leftRow < rows; leftRow++) {
        let rowSum = new Array(cols).fill(0); // Array to store the sum of elements between the two rows
        for (let rightRow = leftRow; rightRow < rows; rightRow++) {
            // Update the sum for each column within the row range
            for (let col = 0; col < cols; col++) {
                rowSum[col] += matrix[rightRow][col];
            }
            // Find the max subarray sum within the column range that is no larger than k
            maxResult = Math.max(maxResult, maxSumNoLargerThanK(rowSum, k));
        }
    }

    return maxResult;
};

Solution in Java

Java
class Solution {
    // Method to find the maximum sum of a submatrix no larger than k
    public int maxSumSubmatrix(int[][] matrix, int k) {
        // Initialize variables
        int rows = matrix.length; // Number of rows in the matrix
        int cols = matrix[0].length; // Number of columns in the matrix
        int maxSum = Integer.MIN_VALUE; // To keep track of the maximum sum <= k

        // Loop over each pair of columns to define the boundaries of the rectangle
        for (int left = 0; left < cols; left++) {
            // Create an array to store the row sums between the left and right boundaries
            int[] rowSums = new int[rows];

            // Move the right boundary from the left to the end of the matrix
            for (int right = left; right < cols; right++) {
                // Update the rowSums array by adding the values between the left and right boundaries
                for (int row = 0; row < rows; row++) {
                    rowSums[row] += matrix[row][right];
                }

                // Now find the maximum sum of a subarray in rowSums that is <= k
                maxSum = Math.max(maxSum, findMaxSumNoLargerThanK(rowSums, k));
            }
        }

        return maxSum; // Return the maximum sum found
    }

    // Helper method to find the maximum sum of a subarray in rowSums no larger than k
    private int findMaxSumNoLargerThanK(int[] arr, int k) {
        // Use a TreeSet to help find the prefix sums and their differences
        TreeSet<Integer> prefixSums = new TreeSet<>();
        prefixSums.add(0); // Add 0 to the TreeSet to handle subarrays starting from index 0
        int currentSum = 0; // To track the cumulative sum
        int maxSum = Integer.MIN_VALUE; // To track the maximum sum <= k

        for (int num : arr) {
            // Update the current cumulative sum
            currentSum += num;

            // We need to find a prefix sum such that currentSum - prefixSum <= k
            // This means prefixSum >= currentSum - k
            Integer target = prefixSums.ceiling(currentSum - k);

            // If such a prefix sum exists, update the maxSum
            if (target != null) {
                maxSum = Math.max(maxSum, currentSum - target);
            }

            // Add the current cumulative sum to the TreeSet
            prefixSums.add(currentSum);
        }

        return maxSum; // Return the maximum sum found for this subarray
    }
}

Subscribe
Notify of

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments

Popular