矩形区域不超过 K 的最大数值和[二维前缀和]

169 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,矩形区域不超过 K 的最大数值和[二维前缀和] - 掘金 (juejin.cn)

前言

前缀和能用空间换时间,大幅降低时间复杂度,甚至是解题关键。刨析问题的每一个要求,利用问题中的有利条件,来完成解题。

一、矩形区域不超过 K 的最大数值和

image.png

二、前缀和

target : 从矩阵圈一块子矩阵,这些矩阵和小于K,求里面的最大矩阵和。

1-圈子矩阵?确定首行首列尾行尾列,则圈一个子矩阵。

2-子矩阵和?可二维前缀和快速得到子矩阵和。

3-最大矩阵和?用一个变量记录最大值即可。

// 矩阵区域不超过K的最大数值和。
public class MaxSumSubmatrix {
    /*
    target : 从矩阵圈一块子矩阵,这些矩阵和小于K,求里面的最大矩阵和。
    1-圈子矩阵?确定首行首列尾行尾列,则圈一个子矩阵。
    2-子矩阵和?可二维前缀和快速得到子矩阵和。
    3-最大矩阵和?用一个变量记录最大值即可。
     */
    public int maxSumSubmatrix(int[][] matrix, int k) {
        int m = matrix.length, n = matrix[0].length;
        // 构建二维前缀和。
        int[][] prefix = buildPrefix(matrix, m, n);
        // 圈子矩阵:定义好首行首列/尾行尾列即可。
        int max = 1 << 31;
        for (int i = 0; i < m; i++) {
            // bug2:尾列不能比首列还低.
            for (int j = i; j < m; j++) {
                for (int p = 0; p < n; p++) {
                    for (int q = p; q < n; q++) {
                        /*
                         计算当前子矩阵和:
                         prefix[j + 1][q + 1]
                         - prefix[j + 1][p] - prefix[i][q + 1]
                         + prefix[i][p]。
                         */
                        int sum = prefix[j + 1][q + 1]
                                - prefix[j + 1][p] - prefix[i][q + 1]
                                + prefix[i][p];
                        // 判断其是否超过了k
                        if (sum == k) return k;
                        if (sum < k && sum > max) max = sum;
                    }
                }
            }
        }
        return max;
    }

    // 构建二维矩阵前缀和。
    private int[][] buildPrefix(int[][] matrix, int m, int n) {
        int[][] prefix = new int[m + 1][n + 1];
        // 二维前缀和定义:prefix[i][j] = prefix[i-1][j] + prefix[i][j-1]
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                // bug1:前缀和,除了前缀,还要加上自己。
                // bug2:前缀和定义出错,加上左 + 上边 - 去重 + 自己
                // prefix[i][j] = prefix[i - 1][j] + prefix[i][j - 1] + matrix[i - 1][j - 1];
                prefix[i][j] = prefix[i][j - 1]
                        + prefix[i - 1][j]
                        - prefix[i - 1][j - 1]
                        + matrix[i - 1][j - 1];
            }
        }
        return prefix;
    }

    public static void main(String[] args) {
        new MaxSumSubmatrix().maxSumSubmatrix(new int[][]{{5, -4, -3, 4}, {-3, -4, 4, 5}, {5, 1, 5, -4}}, 3);
    }
}

注:这里不能用dp来抛弃负数,不是单纯的求最大值,如果K为大负数,就凉凉。

总结

1)前缀和;

2)问题刨析。

参考文献

[1] LeetCode 矩形区域不超过 K 的最大数值和