最后更新于
最后更新于
给定一个二维矩阵,计算其子矩形范围内元素的总和,该子矩阵的左上角为 (row1, col1) ,右下角为 (row2, col2) 。
上图子矩阵左上角 (row1, col1) = (2, 1) ,右下角(row2, col2) = (4, 3),该子矩形内元素的总和为 8。
示例:
提示:
你可以假设矩阵不可变。
会多次调用 sumRegion 方法。
你可以假设 row1 ≤ row2 且 col1 ≤ col2 。
依然沿用前缀和的思路, 只不过由一维扩展到了二维.
使用一个二维数组记录前缀和, 由于是二维数组, 这里的前缀和f(i, j)定义为(0, 0)到(i, j)子矩阵的所有元素之和. 那么在计算前缀和时, 还是需要使用动态规划的方法.
在求f(i, j)之前, 我们已经知道了f(i-1, j-1), f(i-1, j), f(i, j-1)的值, 为了覆盖所有方格, 先求f(i-1, j)和f(i, j-1)之和, 但由于加了两次f(i-1, j-1)部分, 需要减去一次f(i-1, j-1)部分, 最后再加上新的matrix(i, j)的值. 因此状态转移公式如下图中所示.
得到前缀和之后, 就要考虑求解大矩阵中任意位置的子矩阵元素之和的问题. 如下图所示, 求点A到点D确定的子矩形中所有元素之和记为S(A, D), 那么S(A, D)就要从S(O, D)中来. 为了减去红色和粉红色的部分, 就要将S(O, D)减去S(O, E)再减去S(O, F). 由于灰色部分减去了两次, 所以要加上一次S(O, G).
公式如下:
S(A, D) = S(O, G) - S(O, E) - S(O, F) + S(O, G)
另外还有一点需要特别注意. 如果点D的坐标有一个维度为0, 问题就由二维问题降为一维问题, 这种边界情况在计算前缀和以及求解任意两点的结果时都需要考虑. 而同一维的情况一样, 在创建前缀和矩阵时, 在左侧和上方的外围都添加上一圈0, 这样就将所有问题都转化为矩阵内部的问题, 也就不用考虑边缘情况了.
对比使用与不使用这个技巧的代码复杂度.
不使用:
使用: