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.
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
Constraints:
m == matrix.lengthn == matrix[i].length1 <= m, n <= 100-100 <= matrix[i][j] <= 100-105 <= k <= 105
思路:
一维的presum想必大家都用过, arr=[1, 2, 3, 4, 5], presum=[0, 1, 3, 6, 10, 15]。那二维数组能不能做presum?答案是能。
vec=[
[1, 0, 1]
[0, -2, 3]
[0, 1, 0]
]
我们先计算每行的row_presum = [
[0, 1, 1, 2]
[0, 0, -2, 1]
[0, 0, 1, 1]
]
在根据row_presum每一列累加,得到presum=[
[0, 0, 0, 0, 0]
[0, 0, 1, 1, 2]
[0, 0, 1, -1, 3]
[0, 0, 1, 0, 4]
], 这样presum[i][j]实际表示的是从vec[0][0]到vec[i-1][j-1]这个矩阵的和。有了这个我们计算里面任何一个子矩阵的和就简单多了. 比如我们要计算从vec[1][1]到vec[2][2]这个矩阵的和,我们可以用vec[0][0]到vec[2][2]的和 - vec[0][0]到vec[2][0]的和 - vec[0][0]到vec[0][2]的和 + vec[0][0]到vec[0][0]的和, 之所以最后要加一项是因为前面的两个减项有重叠的部分,而重叠的部分就是vec[0][0]到vec[0][0], 由此我们可以推出, 假设我们把起始点的索引记为Si, Sj, 终止点的索引记为Ei, Ej, 那我们可以推出sum(Si, Sj, Ei, Ej) = presum[Ei+1][Ej+1] - presum[Si][Ej+1] - presum[Ei+1][Sj] + presum[Si][Sj]。求和公式推倒出来了,剩下的就是怎么用了,我是没想出好办法,只能暴力来,外层遍历Ei, Ej, 内层根据Si <= Ei, Sj <= Ej再便利Si, Sj, 复杂度应该是O(n2), 但是提交的时候也通过了.
代码(Rust):
impl Solution {
pub fn max_sum_submatrix(matrix: Vec<Vec<i32>>, k: i32) -> i32 {
let row_presum: Vec<Vec<i32>> = matrix
.iter()
.map(|row| {
row.iter().fold(vec![0], |mut l, v| {
let last = l.last().unwrap();
l.push(*v + *last);
l
})
})
.collect();
let mut presum = vec![vec![0; matrix[0].len() + 1]; matrix.len() + 1];
for col in 1..matrix[0].len() + 1 {
let mut sum = 0;
for row in 1..matrix.len() + 1 {
sum += row_presum[row - 1][col];
presum[row][col] = sum;
}
}
let area = |srow: usize, scol: usize, erow: usize, ecol: usize| -> i32 {
presum[erow + 1][ecol + 1] - presum[erow + 1][scol] - presum[srow][ecol + 1]
+ presum[srow][scol]
};
let mut max = -10001;
for end_row in 0..matrix.len() {
for end_col in 0..matrix[0].len() {
for start_row in 0..=end_row {
for start_col in 0..=end_col {
let a = area(start_row, start_col, end_row, end_col);
if a > k {
continue;
} else {
max = max.max(a);
}
}
}
}
}
max
}
}
本文介绍了如何解决一个二维数组中找到最大子矩阵和不超过k的问题。通过计算每行的前缀和,然后进一步计算整个二维数组的前缀和矩阵,可以有效地找出满足条件的子矩阵的最大和。文章提供了具体的算法实现,虽然采用的是暴力方法,但已成功通过了所有测试用例。
1282

被折叠的 条评论
为什么被折叠?



