与动态规划的爱恨情仇——矩阵区域和

72 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第20天,点击查看活动详情


最近一直在力扣刷题,也逐渐对各类题型有了自己的理解,所谓见招拆招,将自己的浅显经验分享一下,帮助更多在编程路上的朋友们。


矩阵区域和

给你一个 m x n 的矩阵 mat 和一个整数 k ,请你返回一个矩阵 answer ,其中每个 answer[i][j] 是所有满足下述条件的元素 mat[r][c] 的和: 

  • i - k <= r <= i + k,
  • j - k <= c <= j + k 且
  • (r, c) 在矩阵内。

 

示例 1:

输入: mat = [[1,2,3],[4,5,6],[7,8,9]], k = 1
输出: [[12,21,16],[27,45,33],[24,39,28]]

示例 2:

输入: mat = [[1,2,3],[4,5,6],[7,8,9]], k = 2
输出: [[45,45,45],[45,45,45],[45,45,45]]

 

提示:

  • m == mat.length
  • n == mat[i].length
  • 1 <= m, n, k <= 100
  • 1 <= mat[i][j] <= 100

思路

要求一个区域内所有元素的和,如果暴力求解的话会非常耗时,所以采用前缀和的方法。

对于二维数组的前缀和,求的是当前位置左上方所有元素的和。在初始化前缀和数组时,只需要将其上方和左方的前缀和加起来,再减去左上方的前缀和,加上当前位置元素即可。

在求区域和时,也是同理,要获取当前区域和,需要右下角的前缀和 - 左边界前缀和 - 上边界前缀和 + 左上角前缀和。

题解

class Solution {
    public int[][] matrixBlockSum(int[][] mat, int k) {
        int m = mat.length;
        int n = mat[0].length;
        int[][] preSum = new int[m + 1][n + 1];
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                preSum[i + 1][j + 1] = preSum[i][j + 1] + preSum[i + 1][j] - preSum[i][j] + mat[i][j];
            }
        }
        int[][] ans = new int[m][n];
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                int pi = 1 + (i + k >= m? m - 1: i + k);
                int pj = 1 + (j + k >= n? n - 1: j + k);
                int ni = i - k < 0? 0: i - k;
                int nj = j - k < 0? 0: j - k;
                ans[i][j] = preSum[pi][pj] - preSum[ni][pj] - preSum[pi][nj] + preSum[ni][nj];
            }
        }
        return ans;
    }
}