[LeetCode0304题二维区域和检索 - 矩阵不可变]

前言

昨天做了[LeetCode0303题区域和检索 - 数组不可变] | 刷题打卡[LeetCode1200. 最小绝对差] | 刷题打卡两道题,303题是昨天的每日一题考察的是前缀和,果然今天的每日一题也是,其实大家从每天的每日一题点进相似题目,如果看到官方题解更新了,那这道题大概率就是第二天的每日一题了。

题目描述

这题是LeetCode0304题二维区域和检索 - 矩阵不可变,也是今天的每日一题。

给定一个二维矩阵,计算其子矩形范围内元素的总和,该子矩阵的左上角为 (row1, col1) ,右下角为 (row2, col2)。

上图子矩阵左上角 (row1, col1) = (2, 1) ,右下角(row2, col2) = (4, 3),该子矩形内元素的总和为 8。

示例:

给定 matrix = [
  [3, 0, 1, 4, 2],
  [5, 6, 3, 2, 1],
  [1, 2, 0, 1, 5],
  [4, 1, 0, 1, 7],
  [1, 0, 3, 0, 5]
]

sumRegion(2, 1, 4, 3) -> 8
sumRegion(1, 1, 2, 2) -> 11
sumRegion(1, 2, 2, 4) -> 12

说明:

  • 你可以假设矩阵不可变。
  • 会多次调用 sumRegion 方法。
  • 你可以假设 row1 ≤ row2 且 col1 ≤ col2。

解题思路

看到题目就想到了昨天的每日一题前缀和,然后看了下题目描述考察的也是前缀和,那还等什么?直接按照昨天的思路开始来吧!

定义一个sum新数组,和给定数组matrix一样,只不过全部填充为0,这里记得要先判断matrix的length,我第一遍做的时候没有对matrix的length进行判断就出错了,考虑到sum[0][0]的情况后面还需要特殊处理,所以我们在定义sum的时候sum.length = matrix.length+1,sum[0].length = matrix[0].length+1。

我们以示例为数据,则sum如下所示:

[
  [ 0, 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0, 0 ]
]

然后就是循环matrix计算前缀和,前面我们考虑到sum[0][0]的情况对sum进行了处理,所以坐标[i, j]可以在sum中表示为sum[i+1][j+1],我们以matrix[1][1]为例它的前缀和是14(从图中一个一个算,这是最笨的方法了吧),可以表示为sum[2][2],如下所示:

sum[2][2] = sum[1][2] + sum[2][1] + matrix[1][1]

// sum[1][2]表示的是当前位置上一行的前缀和即matrix[0][1]的前缀和,从图中可以看出是3
// sum[2][1]表示这一行当前位置的前缀和即matrix[1][0]的前缀和,从图中可以看出是8
// 加上当前位置 matrix[1][1] = 6
// 得到 17

这里得到的17和我们上面用笨方法得到的14不对啊,是方法错了吗?

不是的,我们仔细看会发现,sum[1][2]和sum[2][1]是不是都计算了一遍sum[1][1],这里进行了重复计算前缀和,所以要减掉一个sum[1][1],即如下所示:

sum[2][2] = sum[1][2] + sum[2][1] - sum[1][1] + matrix[1][1] = 3 + 8 - 3 + 6 = 14

即:

this.sum[i + 1][j + 1] = this.sum[i][j + 1] + this.sum[i + 1][j] - this.sum[i][j] + matrix[i][j];

然后我们以sumRegion(2, 1, 4, 3)为例来演示,即求matrix[2][1]到matrix[4][3]之间的元素和,有的同学会说这里直接这样做:

sum[5][4] - sum[3][2]

// 等于 19

可以看出这样是不对的,看下图:

matrix[4][3]的前缀和是matrix[0][0]到matrix[4][3],先减掉matrix[1][3],剩下的就是matrix[2][0]到matrix[4][3]的元素和了,然后再减去matrix[4][0],剩下的就是matrix[2][1]到matrix[4][3]的元素和吗?当然不是,我们可以发现我们多减了一个matrix[1][0]的元素和,所以要再加上matrix[1][0]的元素和,最后得到的就是matrix[2][1]到matrix[4][3]之间的元素和。

复杂度分析

  • 时间复杂度:初始化 O(mn)O(mn),每次检索 O(1)O(1),其中 mm 和 nn 分别是矩阵 \textit{matrix}matrix 的行数和列数。

    初始化需要遍历矩阵 \textit{matrix}matrix 计算二维前缀和,时间复杂度是 O(mn)O(mn)。

    每次检索的时间复杂度是 O(1)O(1)。

  • 空间复杂度:O(mn)O(mn),其中 mm 和 nn 分别是矩阵 \textit{matrix}matrix 的行数和列数。需要创建一个 m+1m+1 行 n+1n+1 列的二维前缀和数组 \textit{sums}sums。

解题代码

/**
* @param {number[][]} matrix
*/
var NumMatrix = function (matrix) {
 const m = matrix.length;
 if (m > 0) {
   const n = matrix[0].length;
   this.sum = new Array(m + 1).fill(0).map(() => new Array(n + 1).fill(0));
   for (let i = 0; i < m; i++) {
     for (let j = 0; j < n; j++) {
       this.sum[i + 1][j + 1] = this.sum[i][j + 1] + this.sum[i + 1][j] - this.sum[i][j] + matrix[i][j];
     }
   }
 }
};

/** 
* @param {number} row1 
* @param {number} col1 
* @param {number} row2
* @param {number} col2
* @return {number}
*/
NumMatrix.prototype.sumRegion = function (row1, col1, row2, col2) {
 return this.sum[row2 + 1][col2 + 1] - this.sum[row1][col2 + 1] - this.sum[row2 + 1][col1] + this.sum[row1][col1];
};

/**
* Your NumMatrix object will be instantiated and called as such:
* var obj = new NumMatrix(matrix)
* var param_1 = obj.sumRegion(row1,col1,row2,col2)
*/

总结

这道题和昨天303的题虽然都是前缀和,但是303是一维前缀和,这道题是二维前缀和,当然用一维也可以(具体的解法就要大家自己去思考了)。如果你觉的还不错的话,给我点个赞吧💐

加油!好兄弟们!💪💪💪

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值