假设原二维矩阵的最大子矩阵所在行是从i到j,那么只会出现下面这2种情况:
- 当i=j时,求最大子矩阵和就转换成了求第i行元素的最大连续子序列和。
- 当i!=j时,将第i行到第j行的所有行的元素累加起来,得到只有一行的一维数组,这个一维数组的最大连续子序列和,便是最大子矩阵和。
只需要从小到大枚举并依次遍历i和j,并且记录当前最大子矩阵和,即可求得最大子矩阵和。
当i!=j时,可以使用一个辅助二维矩阵,记录原始矩阵从上到下累加起来的累加矩阵,于是求从第i行到第j行的一维数组时,只需要将辅助矩阵进行一行减法便可得到,而不需要逐行进行多次累加。
当i!=j时,可以使用一个辅助二维矩阵,记录原始矩阵从上到下累加起来的累加矩阵,于是求从第i行到第j行的一维数组时,只需要将辅助矩阵进行一行减法便可得到,而不需要逐行进行多次累加。
import java.util.*; public class Main { /** * 获得一维数组array的最大连续子序列和 */ private static int findGreatestSumOfSubArray(int[] array) { if (array.length == 0) { return 0; } int[] dp = new int[array.length]; dp[0]=array[0]; int max = array[0]; for(int i=1;i<array.length;i++){ dp[i]=Math.max(dp[i-1]+array[i],array[i]); max=Math.max(max,dp[i]); } return max; } /** * 获得矩阵matrix的最大子矩阵和 */ private static int findGreatestSumOfSubMatrix(int[][] matrix) { int[][] total = matrix;//辅助矩阵 /** * 为了能够在原始矩阵里很快得到从 i 行到 j 行 的上下值之和,我们这里用到了一个辅助矩阵,它是原始矩阵从上到下加下来的 */ for (int i = 0; i < matrix.length; i++) {//初始化辅助矩阵 for (int j = 0; j < matrix[0].length; j++) { if (i == 0) { total[i][j] = matrix[i][j]; } else { total[i][j] += total[i - 1][j]; } } } int ans = Integer.MIN_VALUE; //最大子矩阵为i到j行,i从0到length-1,j从i到length-1 for (int i = 0; i < matrix.length; i++) { for (int j = i; j < matrix.length; j++) { //array 保存的是从 i 行 到第 j 行 所对应的矩阵上下值的和 int[] array = new int[matrix[0].length]; for (int k = 0; k < matrix[0].length; k++) { //如果我们要求第 i 行到第 j 行之间上下值的和,我们可以通过total[j][k] - total[i-1][k] 得到, //k 的范围从1 到 matrix[0].length - 1。 if (i == 0) { //i为0,获得前j行的和 array[k] = total[j][k]; } else { //i不为0,需要减去前i行的和,得到i行到j行的和 array[k] = total[j][k] - total[i - 1][k]; } } int max = findGreatestSumOfSubArray(array); ans = Math.max(max, ans); } } return ans; } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { int n = scanner.nextInt(); int[][] matrix = new int[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { matrix[i][j] = scanner.nextInt(); } } System.out.println(findGreatestSumOfSubMatrix(matrix)); } } }