Bootstrap

【算法】二维子矩阵的和

数组值随机

1  2  3  4  5  6
      ____
2  3 |4  5| 6  7
     |    |
3  4 |5  6| 7  8
     |____|
4  5  6  7  8  9


//sums 回头看,第一遍忽略。添加 0 边界,充当缓冲区
0  0  0  0  0  0  0
         ____
0  1  2 |3  4| 5  6
        |    |
0  2  3 |4  5| 6  7
        |    |
0  3  4 |5  6| 7  8
        |____|
0  4  5  6  7  8  9

求左上角坐标(1,2)到右下角坐标(2,3)的子矩阵的和

首先,两个问题:

(1)如何得到子矩阵的值

(2)如何计算每一个点前缀和

解决第一个问题:

定义二维数组 sums[i][j] 表示,从左上角坐标(0,0)到右下角坐标(i,j)矩阵的和

如何得到左上角坐标(1,2)到右下角坐标(2,3)的子矩阵的和?

抽象一下:

sums[2][3] ——在这里插入图片描述

sums[2][1] ——

sums[0][3] ——在这里插入图片描述

可以看到重复删了 [1,2] ,因此加上 sums[0][1] ——在这里插入图片描述

因此左上角坐标(1,2)到右下角坐标(2,3)的子矩阵的和 = sums[2][3] - sums[2][1] -sums[0][3] + sums[0][1]

化为公式:

左上角坐标(i1,j1)到右下角坐标(i2,j2)的子矩阵的和 = sums[i2][j2] - sums[i2][j1 - 1] - sums[i1 - 1][j2] + sums[i1 - 1][j1 - 1]

解决第二个问题:

sums[2][3] 表示:
在这里插入图片描述

初始化是一个遍历过程,因此假设 sums[2][3] 前的元素已经初始化完成

很简单,两部分构成 sums[2][3] = sums[1][3] + 当前行的 sum[3]
在这里插入图片描述

外循环是行,内循环是列

抽象一下:sums[i][j] = sums[i - 1][j] + 当前行的 sum[j]

细节值得注意: sums[0][3] ——在这里插入图片描述

当左上角坐标是 (1,2)时,减去的一部分坐标为 sums[0][3],也就是索引 i 到 0 了

如果左上角坐标是 (0,2)时呢?在这里插入图片描述

这一部分坐标将是 (-1,3)了,以此为了索引不越界问题,sums[i+1][j+1] 数组定义表示,从左上角坐标(0,0)到右下角坐标(i,j)矩阵的和
在这里插入图片描述

所以公式也将发生变化:

左上角坐标(i1,j1)到右下角坐标(i2,j2)的子矩阵的和 = sums[i2 + 1][j2 + 1] - sums[i2 + 1][j1] - sums[i1][j2 + 1] + sums[i1][j1]

(0,0)到(i,j)的矩阵和 sums[i + 1][j + 1] = sums[i][j + 1] + 当前行的 sum[j + 1]

import java.util.*;

public class Test{
    public static void main(String[] args) {
        int[][] arr = {
                {1,2,3,4,5},
                {2,3,4,5,6},
                {3,4,5,6,7},
                {4,5,6,7,8},
                {5,6,7,8,9}
        };

        System.out.println(subMatrixSum(arr,1,2,3,4));
    }

    private static int subMatrixSum(int[][] arr,int row1,int col1,int row2,int col2) {
        int[][] sums = new int[arr.length + 1][arr[0].length + 1];
        for(int i = 0; i < arr.length; i++) {
            int rowSum = 0;
            for(int j = 0; j < arr[0].length; j++) {
                rowSum += arr[i][j];
                sums[i+1][j+1] = sums[i][j+1] + rowSum;
            }
        }

        return subMatrixSumCore(sums,row1,col1,row2,col2);
    }

    private static int subMatrixSumCore(int[][] sums,int row1,int col1,int row2,int col2) {
        return sums[row2+1][col2+1] - sums[row1][col2+1] - sums[row2+1][col1] + sums[row1][col1];
    }
}
54
;