[Algorithm] Maximum submatrix (dp) (detailed comments)

topic

Given an N × M matrix of positive integers, negative integers, and 0s, write code to find the submatrix with the largest sum of elements.

Returns an array [r1, c1, r2, c2], where r1 and c1 respectively represent the row number and column number of the upper left corner of the submatrix, and r2 and c2 respectively represent the row number and column number of the lower right corner. If there are multiple submatrices that meet the conditions, any one can be returned.

Note: This question has been slightly modified from the original question in the book.

Example:

Input:
[
[-1,0],
[0,-1]
]
Output : [0,1,0,1]
Explanation : The bold element in the input is the matrix represented by the output

illustrate:

  • 1 <= matrix.length, matrix[0].length <= 200

Source: LeetCode
link: https://leetcode-cn.com/problems/max-submatrix-lcci

DP

Ideas

Convert two dimensions to one dimension, convert the maximum submatrix to find the maximum subsequence sum, and use the vertical accumulation array to find the maximum subsequence sum.

  1. Fix the upper bound of the row number of the submatrix and create a new vertical accumulation array
  2. Fixed submatrix row number lower bound
  3. Move the right boundary of the column number and calculate the maximum subsequence sum of the vertical accumulation array
  4. Loop through the lower bound
  5. Loop through the upper bound

code

class Solution {
    
    
    public int[] getMaxMatrix(int[][] matrix) {
    
    
        int n = matrix.length;
        int m = matrix[0].length;
        int max = Integer.MIN_VALUE;

        // 小矩阵元素之和
        int dp = 0;
        // 左边界,也就是左上角点的x坐标
        int start = 0;
        int[] res = new int[4];
        int[] sum;

        // 小矩阵的第一行
        for (int i = 0; i < n; i++) {
    
    
            // sum是纵向累加数组 放在第一层循环当中
            sum = new int[m];
            // 小矩阵的最后一行
            for (int j = i; j < n; j++) {
    
    
                // dp压缩后横向累加数组  start是小矩阵的最左边
                dp = 0;
                start = 0;
                // 当矩阵的上下固定下来 k++表示右列的移动
                for (int k = 0; k < m; k++) {
    
    
                    // 纵向累加数组加一个数字
                    sum[k] += matrix[j][k];
                    // 加上一个列的值
                    // dp+表示矩阵右下表往右了一点,宽度增大了 dp表示压缩过后一行的和,也就是矩阵的和
                    dp += sum[k];
                    // 三层循环 每次都总结一下最大值 max
                    if (max < dp) {
    
    
                        res[0] = i; res[1] = start;
                        res[2] = j; res[3] = k;
                        max = dp;
                    }
                    /*当矩阵的大小也就是dp的值小于0,根据我们在 最大子序和(53题)的基础,
                        动态转移方程是 f(n)=nums[i]+Math.max(0,f(n-1))  懂的都懂
                        这里就是把当前矩阵的元素总和dp与0比较
                        大于则可以不移动左边界 start,随着循环k++移动右边界
                        此时不需要刷新dp的值 而是添加随着右边界移动增加值
                        小于就需要移动左边界 到当前右边界的右边一列 同时刷新dp的值为0,毕竟是重新开始一个矩阵
                        此时 令左边界 start=k+1 下一次循环之后k++,
                        于是左右边界重合,此时无矩阵,矩阵的元素和dp当然是0咯
                    */
                    if (dp < 0) {
    
    
                        dp = 0;
                        start = k + 1;
                    }
                }
            }
        }
        return res;
    }
}

Guess you like

Origin blog.csdn.net/weixin_45177370/article/details/120684109