题目如下:
给定一个正整数、负整数和 0 组成的 N × M 矩阵,编写代码找出元素总和最大的子矩阵。
返回一个数组 [r1, c1, r2, c2],其中 r1, c1 分别代表子矩阵左上角的行号和列号,r2, c2 分别代表右下角的行号和列号。若有多个满足条件的子矩阵,返回任意一个均可。
思路如下:
本题的子问题为《LeetCode 53.最大子序和》,不同的是本题为二维矩阵,因此需要将二维矩阵“打成”一维,然后套用最大子串和,打的手段是使用preSum前缀和,能够在O(1)的时间复杂度内求得。整体是用3-for三层循环,在最内层循环里使用最大子序和的dp算法,鉴于题目给的输入范围为200以内,所以时间上也能过得去。代码如下:
代码
class Solution {
public int[] getMaxMatrix(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
int[][] preSum = new int[m][n];
for(int i = 0; i < n; i++) {
preSum[0][i] = matrix[0][i];
for(int j = 1; j < m; j++) {
preSum[j][i] = preSum[j-1][i] + matrix[j][i];
}
}
int[] res = new int[4];
int max = Integer.MIN_VALUE;
for(int i = m-1; i >= 0; i--) {
for(int j = 0; j <= i; j++) {
int begin = 0;
int temp = 0;
//开始最大子序和的dp求解
int sum = 0, ans = 0;
for(int k = 0; k < n; k++) {
temp = preSum[i][k] - (j>0 ? preSum[j-1][k] : 0);
if(sum > 0) {
sum += temp;
}else {
sum = temp;
begin = k;
}
if(sum > max) {
max = sum;
res[0] = j; res[2] = i; res[1] = begin; res[3] = k;
}
}
}
}
return res;
}
}