二维区域和检索 - 矩阵不可变

Posted by zhouqian on Sunday, July 24, 2022

力扣 304. 二维区域和检索 - 矩阵不可变

给定一个二维矩阵 matrix,以下类型的多个请求:

计算其子矩形范围内元素的总和,该子矩阵的 左上角 为 (row1, col1) ,右下角 为 (row2, col2) 。 实现 NumMatrix 类:

  • NumMatrix(int[][] matrix) 给定整数矩阵 matrix 进行初始化
  • int sumRegion(int row1, int col1, int row2, int col2) 返回 左上角 (row1, col1)、右下角(row2,col2) 所描述的子矩阵的元素 总和 。

方案一:使用前缀和配合无序映射。

type NumMatrix struct {
    preSum [][]int // 二维前缀和数组
}


func Constructor(matrix [][]int) NumMatrix {
    // 构建二维数组计算前缀和,下标从 1 开始可以减少边界判断,所以前缀和数组长度较原数组大 1
    m , n := len(matrix), len(matrix[0])
    preSum := make([][]int, m + 1)
    for i := range preSum {
        preSum[i] = make([]int, n + 1)
    }

    for i := 1; i <= m; i++ {
        for j := 1; j <= n; j++ {
            // 计算前缀和
            preSum[i][j] = preSum[i - 1][j] + preSum[i][j - 1] - 
                preSum[i - 1][j - 1] + matrix[i - 1][j - 1]
        }
    }
    return NumMatrix{
        preSum: preSum,
    }
}


func (this *NumMatrix) SumRegion(row1 int, col1 int, row2 int, col2 int) int {
    // 因为计算前缀和时下标加了一,所以 row1, col1 处的前缀和其实是 preSum[row1 + 1][col1 + 1]
    return this.preSum[row2 + 1][col2 + 1] - 
        this.preSum[row1][col2 + 1] - this.preSum[row2 + 1][col1] + 
        this.preSum[row1][col1]
}


/**
 * Your NumMatrix object will be instantiated and called as such:
 * obj := Constructor(matrix);
 * param_1 := obj.SumRegion(row1,col1,row2,col2);
 */
  • 时间复杂度:O(m * n),构造函数在运行时需要遍历所有元素,所以时间复杂度在 O(m * n),而 SumRegion 函数不涉及复杂操作,时间复杂度在 O(1)。
  • 空间复杂度:O(m * n),是因为使用了长度为 (m+1) * (n + 1) 的二维数组保存了前缀和,所以空间复杂度为 O(m * n)。