Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper left corner (row1, col1) and lower right corner (row2, col2).html
The above rectangle (with the red border) is defined by (row1, col1) = (2, 1) and (row2, col2) = (4, 3), which contains sum = 8. java
Example:
数组
Given 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 update(3, 2, 2) sumRegion(2, 1, 4, 3) -> 10
Note:
ide
这道题让咱们求二维区域和检索,并且告诉咱们数组中的值可能变化,这是以前那道Range Sum Query 2D - Immutable的拓展,因为咱们以前作过一维数组的可变和不可变的状况Range Sum Query - Mutable和Range Sum Query - Immutable,那么为了可以经过OJ,咱们仍是须要用到树状数组Binary Indexed Tree(参见Range Sum Query - Mutable),其查询和修改的复杂度均为O(logn),那么咱们仍是要创建树状数组,咱们根据数组中的每个位置,创建一个二维的树状数组,而后还须要一个getSum函数,以便求得从(0, 0)到(i, j)的区间的数字和,而后在求某一个区间和时,就利用其四个顶点的区间和关系能够快速求出,参见代码以下:函数
解法一:post
// Binary Indexed Tree class NumMatrix { public: NumMatrix(vector<vector<int>> &matrix) { if (matrix.empty() || matrix[0].empty()) return; mat.resize(matrix.size() + 1, vector<int>(matrix[0].size() + 1, 0)); bit.resize(matrix.size() + 1, vector<int>(matrix[0].size() + 1, 0)); for (int i = 0; i < matrix.size(); ++i) { for (int j = 0; j < matrix[i].size(); ++j) { update(i, j, matrix[i][j]); } } } void update(int row, int col, int val) { int diff = val - mat[row + 1][col + 1]; for (int i = row + 1; i < mat.size(); i += i&-i) { for (int j = col + 1; j < mat[i].size(); j += j&-j) { bit[i][j] += diff; } } mat[row + 1][col + 1] = val; } int sumRegion(int row1, int col1, int row2, int col2) { return getSum(row2 + 1, col2 + 1) - getSum(row1, col2 + 1) - getSum(row2 + 1, col1) + getSum(row1, col1); } int getSum(int row, int col) { int res = 0; for (int i = row; i > 0; i -= i&-i) { for (int j = col; j > 0; j -= j&-j) { res += bit[i][j]; } } return res; } private: vector<vector<int>> mat; vector<vector<int>> bit; };
我在网上还看到了另外一种解法,这种解法并无用到树状数组,而是利用了列之和,所谓列之和,就是(i, j)就是(0, j) + (1, j) + ... + (i, j) 之和,至关于把不少个一维的区间之和拼到了一块儿,那么咱们在构造函数中须要创建起这样一个列之和矩阵,而后再更新某一个位置时,咱们只须要将该列中改变的位置下面的全部数字更新一下便可,而在求某个区间和时,只要将相差的各列中对应的起始和结束的行上的值的差值累加起来便可,参见代码以下:url
解法二:spa
// Column Sum class NumMatrix { public: NumMatrix(vector<vector<int>> &matrix) { if (matrix.empty() || matrix[0].empty()) return; mat = matrix; colSum.resize(matrix.size() + 1, vector<int>(matrix[0].size(), 0)); for (int i = 1; i < colSum.size(); ++i) { for (int j = 0; j < colSum[0].size(); ++j) { colSum[i][j] = colSum[i - 1][j] + matrix[i - 1][j]; } } } void update(int row, int col, int val) { for (int i = row + 1; i < colSum.size(); ++i) { colSum[i][col] += val - mat[row][col]; } mat[row][col] = val; } int sumRegion(int row1, int col1, int row2, int col2) { int res = 0; for (int j = col1; j <= col2; ++j) { res += colSum[row2 + 1][j] - colSum[row1][j]; } return res; } private: vector<vector<int>> mat; vector<vector<int>> colSum; };
相似题目:code
Range Sum Query 2D - Immutablehtm
参考资料:
https://leetcode.com/discuss/70948/15ms-easy-to-understand-java-solution
https://leetcode.com/discuss/71169/java-2d-binary-indexed-tree-solution-clean-and-short-17ms