矩形区域不超过 K 的最大数值和
难度:
标签:
题目描述
给你一个 m x n
的矩阵 matrix
和一个整数 k
,找出并返回矩阵内部矩形区域的不超过 k
的最大数值和。
题目数据保证总会存在一个数值和不超过 k
的矩形区域。
示例 1:

输入:matrix = [[1,0,1],[0,-2,3]], k = 2
输出:2
解释:蓝色边框圈出来的矩形区域 [[0, 1], [-2, 3]]
的数值和是 2,且 2 是不超过 k 的最大数字(k = 2)。
示例 2:
输入:matrix = [[2,2,-1]], k = 3 输出:3
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 100
-100 <= matrix[i][j] <= 100
-105 <= k <= 105
进阶:如果行数远大于列数,该如何设计解决方案?
代码结果
运行时间: 520 ms, 内存: 16.9 MB
/*
* 思路:
* 使用Java Streams来计算前缀和和最大矩形区域和的求解。我们将尽可能使用流操作来替代传统的循环结构。
*/
import java.util.*;
import java.util.stream.*;
public class MaxSumRectangleNoLargerThanKStream {
public int maxSumSubmatrix(int[][] matrix, int k) {
int rows = matrix.length;
int cols = matrix[0].length;
int maxSum = Integer.MIN_VALUE;
int[][] prefixSum = new int[rows + 1][cols + 1];
// 计算前缀和
IntStream.range(1, rows + 1).forEach(i ->
IntStream.range(1, cols + 1).forEach(j ->
prefixSum[i][j] = matrix[i - 1][j - 1] + prefixSum[i - 1][j] + prefixSum[i][j - 1] - prefixSum[i - 1][j - 1]
)
);
// 遍历所有的矩形区域
maxSum = IntStream.range(1, rows + 1).boxed().flatMap(i ->
IntStream.range(1, cols + 1).boxed().flatMap(j ->
IntStream.range(i, rows + 1).boxed().flatMap(k ->
IntStream.range(j, cols + 1).map(l ->
prefixSum[k][l] - prefixSum[i - 1][l] - prefixSum[k][j - 1] + prefixSum[i - 1][j - 1]
).filter(sum -> sum <= k).boxed()
)
)
).max(Integer::compareTo).orElse(Integer.MIN_VALUE);
return maxSum;
}
}
解释
方法:
此题解采用了前缀和加二分查找的方法来解决问题。首先,我们遍历所有可能的上下边界组合,然后计算这个边界内每一列的和,并将其保存在col_sum数组中。接着,我们利用前缀和的概念来计算从第一列到当前列的所有元素的和,存储在cur_sum中。为了找到一个子矩阵的和不超过k,我们需要在presum数组中查找一个数,使得cur_sum减去这个数不超过k。我们使用二分查找来快速定位这个数,如果找到了满足条件的子矩阵,我们就更新结果res。最终,返回res即可。
时间复杂度:
O(m^2 * n * logn)
空间复杂度:
O(n)
代码细节讲解
🦆
为什么选择使用前缀和和二分查找的组合来解决这个问题?是否有其他更有效的方法?
▷🦆
在计算col_sum时,你是如何处理矩阵中的负数值对总和的影响?
▷🦆
你如何保证在使用bisect_left查找时,得到的presum[index]是满足条件的最小前缀和?
▷🦆
代码中有检查`if matrix[rd][c] == k`的条件,直接返回k。这种情况是否总是存在,需要这样的检查吗?
▷