问题描述
给定一个矩阵matrix,其中的值有正、有负、有0,返回子矩阵的最大累加和。
例如,matrix为:
其中最大累加和的子矩阵为:
2 2
所以返回4。
算法思路
对矩阵按列求和存到数组里,然后再求此数组的子数组的最大累加和,即为矩阵的最大累加和。
以从第一行为例画图解释:
第一行计算后,最大的累加和为2
同理可对第二行…第n行进行计算,最后得到子矩阵的最大累加和。
代码
public class Case06_MaxSubMatrix {
public static void main(String[] args) {
int[][] matrix = {
{-1,-1,-1},
{-1,2,2},
{-1,-1,-1}
};
System.out.println(maxSum(matrix));
}
//求子矩阵的最大累加和O(n^3)
static int maxSum(int[][] matrix) {
int beginRow = 0;//起始行
final int M = matrix.length;
final int N = matrix[0].length;
int[] sums = new int[N];//按列求和
int max = 0;//历史最大的子矩阵和
while(beginRow < M) {
for (int i = beginRow; i < M; i++) {//从起始行到第i行
for (int j = 0; j < N; j++) {//按列累加
sums[j] += matrix[i][j];
}
//累加完成
//求出sums的子数组最大和O(n)
int t = findByDp(sums);
if (t > max) {
max = t;
}
}
//另起一行作为起始行,把sum清零
Arrays.fill(sums,0);//快速地将sums的每个元素都设为0
beginRow++;
}
return max;
}
//递推法 O(n)求子数组的最大累加和
static int findByDp(int[] arr) {
int sumI = arr[0];
int maxSum = sumI;
for (int i=1;i < arr.length;i++) {
if (sumI >= 0) {//左子表的最大和为正,继续向后累加
sumI += arr[i];
} else {//左子表的最大和为负,丢弃左边的,定义右边的第一个为最大和,继续向后加
sumI = arr[i];
}
if (sumI > maxSum) {
maxSum = sumI;
}
}
return maxSum;
}
}
注:findByDp方法是求子数组的最大累加和,在我上一篇博客里有写,想了解请参考:多维数组与矩阵之子数组的最大累加和