Title Description
Given a two-dimensional matrix, multiple requests of the following types:
Calculate the sum of the elements within its sub rectangle. The upper left corner of the sub matrix is (row1, col1) and the lower right corner is (row2, col2).
Implement the NumMatrix class:
NumMatrix(int[][] matrix) initializes the given integer matrix
int sumRegion(int row1, int col1, int row2, int col2) returns the sum of the elements of the submatrix described in the upper left corner (row1, col1) and the lower right corner (row2, col2).
Example 1:
Input:
["NumMatrix","sumRegion","sumRegion","sumRegion"]
[[[[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]]],[2,1,4,3],[1,1,2,2],[1,2,2,4]]
Output:
[null, 8, 11, 12]
Explanation:
NumMatrix numMatrix = new NumMatrix([[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]]]);
numMatrix.sumRegion(2, 1, 4, 3); // return 8 (sum of elements in the red rectangle)
numMatrix.sumRegion(1, 1, 2, 2); // return 11 (sum of elements in the green rectangle)
numMatrix.sumRegion(1, 2, 2, 4); // return 12 (sum of elements in the blue rectangle)
Source: LeetCode
Link: https://leetcode-cn.com/problems/range-sum-query-2d-immutable
Solution 1
Here, we first use the slowest violence method to solve the problem, that is, the sum of elements in the region containing row1,col1 and row2,col2
Here the subscript starts from 0, which is equivalent to giving the range of row and column subscripts row1row2 and col1col2
When testing instance 17, it failed, because the time of testing instance 17 is too long, and the for loop can not pass, but there is no problem with this code
It must be available, but it will timeout
class NumMatrix { vector<vector<int>> matrix; public: NumMatrix(vector<vector<int>>& matrix) { this->matrix = matrix; //Direct value transfer } int sumRegion(int row1, int col1, int row2, int col2) { int sum = 0; //The subscripts given here should all be within the range without crossing the boundary, so there is no need to check. The values at the boundary are included here for(int i = row1; i <= row2; i++) { for(int j = col1; j <= col2; j++) { sum += matrix[i][j]; } } return sum; } };
Here we refer to the idea of 303 one-dimensional prefix sum
One dimensional array prefix sum
If we find a region of 33 here, we can regard it as three lines. In this way, we only need to subtract the value at col2 from the value at col1 to get the sum of one line
In this way, the sum of the three lines can also be obtained
Therefore, we need to accumulate the original matrix in the way of summation. Each row is equivalent to a one-dimensional array. We set a matrix of nn+1 size. Each row stores the prefix and. It doesn't matter between different rows
1. First initialize the construction prefix and
2. Take the corresponding prefix of the corresponding line and subtract, and the result can be added.
It can be compiled, and the memory consumption ratio is acceptable, but the time is too long and the running time is too long.
The time and space complexity is O(mn)
class NumMatrix { vector<vector<int>> sums; public: NumMatrix(vector<vector<int>>& matrix) { int m = matrix.size(); int n = matrix[0].size(); sums.resize(m); for(int i = 0; i < m; i++) { sums[i].resize(n + 1); //Here, sum [0] = 0, and sum [1] = num [0] + sum [0] //Sum [2] = num [1] + sum [1] here, the current value + the sum of the previous ones for(int j = 1; j <= n; j++) { //Current value + previous sum sums[i][j] = matrix[i][j - 1] + sums[i][j - 1]; } } } int sumRegion(int row1, int col1, int row2, int col2) { int sum = 0; //The subscripts given here should all be within the range without crossing the boundary, so there is no need to check. The values at the boundary are included here //Here, the rectangular area is regarded as multiple vector forms, the array in vector form is summed, and then accumulated to obtain the following results for(int i = row1; i <= row2; i++) { sum += (sums[i][col2 + 1] - sums[i][col1]); } return sum; } };
2D array prefix and
Here, when initializing the matrix, construct a two-dimensional prefix sum. The following results are (row2,col2)-(row1, col2) - (row2, col1) + (row1, col1)
The premise of two-dimensional prefix sum is one-dimensional prefix sum. First construct one-dimensional prefix sum, and then add the element of one line from the second line.
1. Firstly, construct two-dimensional prefix and
2. Using (row2, col2) - two boundaries + common boundary
Similar to requiring the red area in the figure, we use the whole figure to subtract the blue area, subtract the purple area, and add the orange area, then it is equal to the red area. Both the blue and purple areas contain this orange area, so two orange areas are lost, so we need to add an orange area.
Note: the official problem solution here is the same as the sum matrix I established and the way to return the solution. The difference is that the official establishment of the sum matrix
The steps are different from mine. The meaning is the same.
Here, the official solution is f(i, j) = f(i-1, j) + f(i, j-1) - f(i-1, j-1) + matrix[i][j]
class NumMatrix { vector<vector<int>> sums; public: NumMatrix(vector<vector<int>>& matrix) { int m = matrix.size(); int n = matrix[0].size(); //Here, the number of rows is m+1 and the number of columns is n+1 //Here, the number of rows and columns is increased by 1 because it needs to be handled separately to avoid 0 sums.resize(m + 1, vector<int>(n + 1)); //Directly set the size to m+1,n+1 //The matrix is constructed here. When the original matrix is a 1 * 1 matrix, an appropriate matrix can also be constructed without error //Here we construct a one-dimensional prefix and //Line 0 is all 0, which is considered for crossing the boundary //Here, the one-dimensional prefix and sum of sums are calculated from the first row and the first column for(int i = 1; i <= m; i++) { //Here, sum [0] = 0, and sum [1] = num [0] + sum [0] //Sum [2] = num [1] + sum [1] here, the current value + the sum of the previous ones for(int j = 1; j <= n; j++) { //Current value + previous sum sums[i][j] = matrix[i - 1][j - 1] + sums[i][j - 1]; } } //Here, the two-dimensional prefix sum is obtained by adding the one-dimensional prefix sum //There is no problem with this prefix and //Calculate the two-dimensional prefix and from the first column of the second row for(int i = 2; i <= m; i++) { for(int j = 1; j <= n; j++) { sums[i][j] += sums[i - 1][j]; } } } //There are still some problems with the region subtraction of the matrix here. An error will be reported when there is only one element int sumRegion(int row1, int col1, int row2, int col2) { //This is equivalent to the outermost large rectangle minus the small rectangles on both sides plus the common part return sums[row2 + 1][col2 + 1] - sums[row1][col2 + 1] - sums[row2 + 1][col1] + sums[row1][col1]; } };
Here are the steps to create the initialization matrix. Let's change it here
1. If we want to calculate the two-dimensional prefix sum of (row, col), we need to know the values of the two positions
2.(row, col) = (row-1, col) + (row, col-1) - (row-1, col-1) + (row, col). Here you need the values of the left and upper elements, and the values of the current element
You can calculate it, so as long as you traverse from top to bottom and from left to right, these positions are known.
3. During initialization, (1, 1) = (0,1) + (1,0) - (0,0) + (1,1), so there are no errors and problems, and we can easily get the results
4. Both the first row and the first column are 0, which are set so as not to process 0 separately.
class NumMatrix { vector<vector<int>> sums; public: NumMatrix(vector<vector<int>>& matrix) { int m = matrix.size(); int n = matrix[0].size(); //Here, the number of rows is m+1 and the number of columns is n+1 //Here, the number of rows and columns is increased by 1 because it needs to be handled separately to avoid 0 sums.resize(m + 1, vector<int>(n + 1)); //Directly set the size to m+1,n+1 //The premise of this is that both the upper and left sides have met the goals and objectives of 0 to the region //Start from the first line, from left to right, so that this condition can be met. //This is actually the same as the prefix and in the previous line, which are accumulated line by line. for(int i = 1; i <= m; i++) { //Line m+1 for(int j = 1; j <= n; j++) { //Line n+1 sums[i][j] = sums[i - 1][j] + sums[i][j - 1] - sums[i - 1][j - 1] + matrix[i - 1][j - 1]; } } } //There are still some problems with the region subtraction of the matrix here. An error will be reported when there is only one element int sumRegion(int row1, int col1, int row2, int col2) { //This is equivalent to the outermost large rectangle minus the small rectangles on both sides plus the common part return sums[row2 + 1][col2 + 1] - sums[row1][col2 + 1] - sums[row2 + 1][col1] + sums[row1][col1]; } };
int main() { //["NumArray", "sumRange", "sumRange", "sumRange"] input //[[[- 2, 0, 3, - 5, 2, - 1]], [0, 2], [2, 5], [0, 5]] input //[null, 1, -1, -3] output //Here, the first one is null. Here, because the first method is called, the return value is null, and others have return values //This means what the parameters corresponding to the method are, that is, what methods are given and what parameters are passed in vector<vector<int>> nums(2, vector<int>(2)); //This is the passed in parameter nums[0][0] = 1; nums[0][1] = 1; nums[1][0] = 1; nums[1][1] = 1; NumMatrix *numArray = new NumMatrix(nums); cout << numArray->sumRegion(0, 0, 0, 0); return 0; }