LeetCode原题:面试题 17.24. 最大子矩阵
题目描述:
*给定一个正整数、负整数和 0 组成的 N × M 矩阵,编写代码找出元素总和最大的子矩阵。
返回一个数组 [r1, c1, r2, c2],其中 r1, c1 分别代表子矩阵左上角的行号和列号,r2, c2 分别代表右下角的行号和列号。若有多个满足条件的子矩阵,返回任意一个均可。
注意:本题相对书上原题稍作改动
示例:
输入:
[
[-1,0],
[0,-1]
]
输出:[0,1,0,1]
解释:输入中标粗的元素即为输出所表示的矩阵
说明:
1 <= matrix.length, matrix[0].length <= 200*
题目思路:
1)做这道题目的前提是弄懂“最大子序和”这道题,本题的思想是把不同行同一列的元素求和,用一维数组对应存储每列的和,再对这个一维数组运用“最大子序和”的求解方法。(数据量最大200,暗示可以开三层for)
2)然后需要记录选中左上角和右下角元素的坐标
2.1)当pre不大于0时,证明左上角坐标更新,此时需要把左上角坐标用变量存储起来。
2.2)当记录最大值的maxSum更新时,证明此时右下角坐标更新,当前和最大的子矩阵已经找出,把当前的横纵坐标记录下来。
3)最后返回记录下标的数组。
public class MaximalSubmatrix {
public static void main(String[] args) {
int[][] arr = new int[][]{{-1,2,3},{-1,-1,-2},{-2,3,1}};
int[] RES = new int[3];
RES = getMaxMatrix(arr);
for(int res : RES){
System.out.print(res + ",");
}
}
public static int[] getMaxMatrix(int[][] matrix) {
int rowLength = matrix.length;//二维数组行数
int colLength = matrix[0].length;//二维数组列数
int sum[] = new int[colLength];//用来记录同一列不同行元素相加的值
int[] res = new int[]{-1,-1,200,200};//记录返回坐标的数组
int maxSum = Integer.MIN_VALUE;//声明变量用来存储最大值,初始值设置为int最小值
int subscriptR = 0 , subscriptC = 0;//用来记录左上角选中元素的坐标
for(int i = 0 ; i < rowLength ; ++i){
Arrays.fill(sum , 0);//每次i+1,意味着要重新开始降维打击了,因此要把sum全部归0
for(int j = i ; j < rowLength ; ++j){
int pre = 0;//pre是最大连续自序和的做法
for(int k = 0 ; k < colLength ; ++k){
sum[k] += matrix[j][k];//降为打击,把遍历过的行的同一列内容分别加到一个一维数组中
if(pre > 0){//如果pre大于0,证明对后面值变大有帮助,此时直接与后面元素相加,并且不需要更新左上角值
pre += sum[k];
}else{//如果pre不大于0,证明这个pre,对后面值变大没有帮助,我们直接用后面的值覆盖pre,并且更新左上角值坐标
pre = sum[k];
subscriptR = i;
subscriptC = k;
}
if(maxSum <= pre){//如果pre大于此时我们的maxSum,证明子矩阵和最大值需要更新,
maxSum = pre;//我们更新maxSum并且记录此时子矩阵最大和对应左上角和右下角坐标
res[0] = subscriptR;//左上角坐标在pre小与0时已经用变量记录下来了
res[1] = subscriptC;
res[2] = j;//右下角坐标就是我们当前遍历到的元素的坐标,第j行,第k列的那个元素
res[3] = k;
}
}
}
}
System.out.println(maxSum);
return res;//返回记录下标的数组即可
}
}