363. Max Sum of Rectangle No Larger Than K (Hard)
Given a non-empty 2D matrix matrix and an integer k, find the max sum of a rectangle in the matrix such that its sum is no larger than k.
Example:
Given matrix = [
[1, 0, 1],
[0, -2, 3]
]
k = 2
The answer is 2
. Because the sum of rectangle [[0, 1], [-2, 3]]
is 2 and 2 is the max number no larger than k (k = 2).
Note:
- The rectangle inside the matrix must have an area > 0.
- What if the number of rows is much larger than the number of columns?
Solution 1: Brute Force + DP 1658 ms
Time Complexity: $$O(n^4)$$
这道题给了我们一个二维数组,让我们求和不超过的K的最大子矩形,那么我们首先可以考虑使用brute force来解,就是遍历所有的子矩形,然后计算其和跟K比较,找出不超过K的最大值即可。就算是暴力搜索,我们也可以使用优化的算法,比如建立累加和,参见之前那道题Range Sum Query 2D - Immutable,我们可以快速求出任何一个区间和,那么下面的方法就是这样的,当遍历到(i, j)时,我们计算sum(i, j),表示矩形(0, 0)到(i, j)的和,然后我们遍历这个矩形中所有的子矩形,计算其和跟K相比,这样既可遍历到原矩形的所有子矩形,参见代码如下:
class Solution {
public:
int maxSumSubmatrix(vector<vector<int>>& matrix, int k) {
if (matrix.empty() || matrix[0].empty()) return 0;
int n = matrix.size(), m = matrix[0].size(), res = INT_MIN;
int dp[n][m];
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
int t = matrix[i][j];
if (i > 0) t += dp[i-1][j];
if (j > 0) t += dp[i][j-1];
if (i > 0 && j > 0) t -= dp[i-1][j-1];
dp[i][j] = t;
for (int r = 0; r <= i; ++r) {
for (int c = 0; c <= j; ++c) {
int d = dp[i][j];
if (r > 0) d -= dp[r-1][j];
if (c > 0) d -= dp[i][c-1];
if (r > 0 && c > 0) d += dp[r-1][c-1];
if (d <= k) res = max(res, d);
}
}
}
}
return res;
}
};
Solution 2: Kadane's Algorithm 975ms
Time Complexity: $$O(n^3*logn)$$
int maxSumSubmatrix(vector<vector<int>>& matrix, int k) {
if (matrix.empty()) return 0;
int row = matrix.size(), col = matrix[0].size(), res = INT_MIN;
for (int l = 0; l < col; ++l) {
vector<int> sums(row,0);
for (int r = l; r < col; ++r) {
int cum = 0;
set<int> cumset;
cumset.insert(0);
for (int i = 0; i < row; ++i) {
sums[i] += matrix[i][r];
// Find the max subarray no more than K
cum += sums[i];
// cum(i, j]: cum[j]-cum[i] <= k
// cum-k: cum[i] >= cum[j]-k
auto it = cumset.lower_bound(cum-k);
if (it != cumset.end()) {
if (res < cum-*it) res = cum-*it;
if (res == k) return k;
}
cumset.insert(cum);
}
}
}
return res;
}
improved version: 49ms
class Solution {
int maxSumArray(vector<int>& arr, int k) {
int sum = 0, res = INT_MIN;
// first, compute maxSumArray
for (int i = 0; i < arr.size(); ++i) { //it's a trick. Maybe O(n) to solve this problem
sum += arr[i];
res = max(sum, res);
if (sum == k) return sum;
if (sum < 0) sum = 0;
}
if (res <= k) return res;
// maxSumArrayNoLargerThank
res = INT_MIN;
sum = 0;
set<int> cumset; cumset.insert(0);
for (int i = 0; i < arr.size(); ++i) {
sum += arr[i];
auto it = cumset.lower_bound(sum-k);
if (it != cumset.end()) res = max(res, sum-*it);
cumset.insert(sum);
}
return res;
}
public:
int maxSumSubmatrix(vector<vector<int>>& matrix, int k) {
if (matrix.size() == 0) return 0;
int m = matrix.size(), n = matrix[0].size(), res = INT_MIN;
for (int l = 0; l < n; ++l) {
vector<int> sum(m, 0);
for (int r = l; r < n; ++r) {
for (int i = 0; i < m; ++i) {
sum[i] += matrix[i][r];
}
int ms = maxSumArray(sum, k);
if (ms == k) return ms;
if (ms < k && ms > res) res = ms;
}
}
return res;
}
};
Solution 3: Merge Sort