Skip to content

Commit 0a7b0fa

Browse files
committed
304
1 parent 6a9aee4 commit 0a7b0fa

File tree

2 files changed

+210
-0
lines changed

2 files changed

+210
-0
lines changed

SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -248,4 +248,5 @@
248248
* [301 题到 400 题](leetcode-301-400.md)
249249
* [301. Remove Invalid Parentheses](leetcode-301-Remove-Invalid-Parentheses.md)
250250
* [303. Range Sum Query - Immutable](leetcode-303-Range-Sum-Query-Immutable.md)
251+
* [304. Range Sum Query 2D - Immutable](leetcode-304-Range-Sum-Query-2D-Immutable.md)
251252
* [更多](more.md)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
# 题目描述(中等难度)
2+
3+
![](https://windliang.oss-cn-beijing.aliyuncs.com/304.jpg)
4+
5+
给定矩阵的左上角坐标和右下角坐标,返回矩阵内的数字累计的和。
6+
7+
# 解法一
8+
9+
[上一道题](https://leetcode.wang/leetcode-303-Range-Sum-Query-Immutable.html) 其实差不多,上一个题是一维空间的累计,这个是二维,没做过上一题,可以先看一下,这里用同样的思路了。
10+
11+
如果我们只看矩阵的某一行,那其实就变成上一题了。所以我们可以提前把每一行各自的累和求出来,然后求整个矩阵的累和的时候,一行一行求即可。
12+
13+
```javascript
14+
/**
15+
* @param {number[][]} matrix
16+
*/
17+
var NumMatrix = function (matrix) {
18+
this.rowsAccumulate = [];
19+
let rows = matrix.length;
20+
if(rows === 0){
21+
return;
22+
}
23+
let cols = matrix[0].length;
24+
for (let i = 0; i < rows; i++) {
25+
let row = [0];
26+
let sum = 0;
27+
for (let j = 0; j < cols; j++) {
28+
sum += matrix[i][j];
29+
row.push(sum);
30+
}
31+
this.rowsAccumulate.push(row);
32+
}
33+
};
34+
35+
/**
36+
* @param {number} row1
37+
* @param {number} col1
38+
* @param {number} row2
39+
* @param {number} col2
40+
* @return {number}
41+
*/
42+
NumMatrix.prototype.sumRegion = function (row1, col1, row2, col2) {
43+
let sum = 0;
44+
for (let i = row1; i <= row2; i++) {
45+
sum = sum + this.rowsAccumulate[i][col2 + 1] - this.rowsAccumulate[i][col1];
46+
}
47+
return sum;
48+
};
49+
50+
/**
51+
* Your NumMatrix object will be instantiated and called as such:
52+
* var obj = new NumMatrix(matrix)
53+
* var param_1 = obj.sumRegion(row1,col1,row2,col2)
54+
*/
55+
```
56+
57+
# 解法二
58+
59+
当然,我们也可以忘记上一道题的解法,重新分析,但思想还是上一题的思想。
60+
61+
我们可以用 `matrixAccumulate[i][j]` 来保存从 `(0, 0)``(i - 1, j - 1)` 矩阵内所有数累计的和。
62+
63+
`matrixAccumulate[0][*]``matrixAccumulate[*][0]` 都置为 `0` ,这样做的好处就是为了统一处理边界的情况,看完下边的解法,可以回过头来思考。
64+
65+
然后和上一道题一样,对于 `(row1, col1)``(row2, col2)` 这两个点组成的矩阵内数字的累计和可以表示为下边的式子。
66+
67+
```javascript
68+
this.matrixAccumulate[row2 + 1][col2 + 1] -
69+
this.matrixAccumulate[row1][col2 + 1] -
70+
this.matrixAccumulate[row2 + 1][col1] +
71+
this.matrixAccumulate[row1][col1]
72+
```
73+
74+
至于为什么这样,可以结合下边的图。
75+
76+
![](https://windliang.oss-cn-beijing.aliyuncs.com/304_1.jpg)
77+
78+
我们要求的是橙色部分的矩阵。只需要用 `(0, 0)``(row2, col2)` 的矩阵,减去 `(0, 0)``(row1, col2)` 的矩阵,再减去 `(0, 0)``(row2, col1)` 的矩阵,最后加上 `(0, 0)``(row1, col1)` 的矩阵。因为 `(0, 0)``(row1, col1)` 的矩阵多减了一次。
79+
80+
然后可以看看坐标的分布,就可以得出上边的式子了。
81+
82+
![](https://windliang.oss-cn-beijing.aliyuncs.com/304_2.jpg)
83+
84+
之所以出现,`row2 + 1``co2 + 1 ` 这种坐标,是因为我们的 `matrixAccumulate[i][j]` 来保存从 `(0, 0)``(i - 1, j - 1)` ,有一个减 `1 ` 的操作。
85+
86+
至于 `matrixAccumulate` 怎么求,我们可以使用上边类似的方法,通过矩阵的加减实现。
87+
88+
![](https://windliang.oss-cn-beijing.aliyuncs.com/304_3.jpg)
89+
90+
`O``A` 的累加,就等于 `A` 位置的值加上 `O``C` 的累加,加上 `O``B` 的累加,减去 `O``D` 的累加。代码的话,就是下边的样子。
91+
92+
```javascript
93+
this.matrixAccumulate[i][j] =
94+
matrix[i-1][j-1] +
95+
this.matrixAccumulate[i - 1][j] +
96+
this.matrixAccumulate[i][j - 1] -
97+
this.matrixAccumulate[i - 1][j - 1];
98+
}
99+
```
100+
101+
总代码就是下边的了。
102+
103+
```javascript
104+
/**
105+
* @param {number[][]} matrix
106+
*/
107+
var NumMatrix = function (matrix) {
108+
this.matrixAccumulate = [];
109+
let rows = matrix.length;
110+
if (rows === 0) {
111+
return;
112+
}
113+
let cols = matrix[0].length;
114+
115+
for (let i = 0; i <= rows; i++) {
116+
let row = [];
117+
for (let j = 0; j <= cols; j++) {
118+
row.push(0);
119+
}
120+
this.matrixAccumulate.push(row);
121+
}
122+
for (let i = 1; i <= rows; i++) {
123+
for (let j = 1; j <= cols; j++) {
124+
this.matrixAccumulate[i][j] =
125+
matrix[i-1][j-1] +
126+
this.matrixAccumulate[i - 1][j] +
127+
this.matrixAccumulate[i][j - 1] -
128+
this.matrixAccumulate[i - 1][j - 1];
129+
}
130+
}
131+
};
132+
133+
/**
134+
* @param {number} row1
135+
* @param {number} col1
136+
* @param {number} row2
137+
* @param {number} col2
138+
* @return {number}
139+
*/
140+
NumMatrix.prototype.sumRegion = function (row1, col1, row2, col2) {
141+
return (
142+
this.matrixAccumulate[row2 + 1][col2 + 1] -
143+
this.matrixAccumulate[row1][col2 + 1] -
144+
this.matrixAccumulate[row2 + 1][col1] +
145+
this.matrixAccumulate[row1][col1]
146+
);
147+
};
148+
149+
/**
150+
* Your NumMatrix object will be instantiated and called as such:
151+
* var obj = new NumMatrix(matrix)
152+
* var param_1 = obj.sumRegion(row1,col1,row2,col2)
153+
*/
154+
```
155+
156+
再分享 [StefanPochmann](https://leetcode.com/problems/range-sum-query-2d-immutable/discuss/75381/C%2B%2B-with-helper) 大神的一个思路,上边我们用 `matrixAccumulate[i][j]` 来保存从 `(0, 0)``(i - 1, j - 1)` 矩阵内所有数累计的和,多了减一。虽然这种思路经常用到,就像字符串截取函数一样,一般都是包括左端点,不包括右端点,但看起来比较绕。
157+
158+
我们可以用 `matrixAccumulate[i][j]` 来保存从 `(0, 0)``(i, j)` 矩阵内所有数累计的和,这样的话,为了避免单独判断边界情况的麻烦,我们可以封装一个函数,对于下标小于 `0` 的边界情况直接返回 `0` ,参考下边的代码。
159+
160+
```java
161+
/**
162+
* @param {number[][]} matrix
163+
*/
164+
var NumMatrix = function (matrix) {
165+
this.matrixAccumulate = matrix;
166+
let rows = matrix.length;
167+
if (rows === 0) {
168+
return;
169+
}
170+
let cols = matrix[0].length;
171+
172+
for (let i = 0; i < rows; i++) {
173+
for (let j = 0; j < cols; j++) {
174+
this.matrixAccumulate[i][j] +=
175+
this.f(i - 1, j) + this.f(i, j - 1) - this.f(i - 1, j - 1);
176+
}
177+
}
178+
};
179+
180+
/**
181+
* @param {number} row1
182+
* @param {number} col1
183+
* @param {number} row2
184+
* @param {number} col2
185+
* @return {number}
186+
*/
187+
NumMatrix.prototype.sumRegion = function (row1, col1, row2, col2) {
188+
return (
189+
this.f(row2, col2) -
190+
this.f(row1 - 1, col2) -
191+
this.f(row2, col1 - 1) +
192+
this.f(row1 - 1, col1 - 1)
193+
);
194+
};
195+
196+
NumMatrix.prototype.f = function (i, j) {
197+
return i >= 0 && j >= 0 ? this.matrixAccumulate[i][j] : 0;
198+
};
199+
200+
/**
201+
* Your NumMatrix object will be instantiated and called as such:
202+
* var obj = new NumMatrix(matrix)
203+
* var param_1 = obj.sumRegion(row1,col1,row2,col2)
204+
*/
205+
```
206+
207+
#
208+
209+
比较简单的一道题,基本上还是上一题的思路,想起来小学求矩形面积了,哈哈。解法二的话两种技巧都是处理边界情况的方法,将边界的逻辑和其他部分的逻辑统一了起来,前一种扩充 `0` 的技巧比较常用。

0 commit comments

Comments
 (0)