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