题目:html
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).java
The above rectangle (with the red border) is defined by (row1, col1) = (2, 1) and (row2, col2) = (4, 3), which contains sum = 8.node
Example:web
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:spring
连接: http://leetcode.com/problems/range-sum-query-2d-mutable/ide
题解:post
二维Range Sum Query mutable,我了个去,第一次Leetcode写了超过140行代码...足够臭长了吧,可是竟然能ac,仍是很高兴 -____-!! 原理是要构建一个2D Segment Tree或者 2D Fenwick Tree。因为上一题是先作的Segment Tree,这回也先写2D Segment Tree。构建2D Segment Tree依然是使用Divide and Conquer,咱们要把整个平面分红4个部分,因此2D Segment Tree也是一个Quad Tree,每一个节点有四个子节点,NW, NE, SW, SE, 节点的sum是四个子节点的sum。这样咱们就能够用与1D Segment Tree相似的方法来写rangeSum以及update。要注意rangeSum时的判断,有好几种状况,比较复杂。ui
2D Segment Tree: Time Complexity - O(mn) build,O(logmn) update, O(logmn) rangeSum , Space Complexity - O(mn) 复杂度算得不是很清楚,极可能不正确,二刷再继续改正。this
public class NumMatrix { private class SegmentTreeNode2D { public int tlRow; public int tlCol; public int brRow; public int brCol; public int sum; public SegmentTreeNode2D nw, ne, sw, se; public SegmentTreeNode2D(int tlRow, int tlCol, int brRow, int brCol) { this.tlRow = tlRow; this.tlCol = tlCol; this.brRow = brRow; this.brCol = brCol; this.sum = 0; } } public SegmentTreeNode2D root; public NumMatrix(int[][] matrix) { if(matrix == null || matrix.length == 0) { return; } root = buildTree(matrix, 0, 0, matrix.length - 1, matrix[0].length - 1); } public void update(int row, int col, int val) { update(root, row, col, val); } private void update(SegmentTreeNode2D node, int row, int col, int val) { if(node.tlRow == row && node.brRow == row && node.tlCol == col && node.brCol == col) { node.sum = val; return; } int rowMid = node.tlRow + (node.brRow - node.tlRow) / 2; int colMid = node.tlCol + (node.brCol - node.tlCol) / 2; if(row <= rowMid) { if(col <= colMid) { update(node.nw, row, col, val); } else { update(node.ne, row, col, val); } } else { if(col <= colMid) { update(node.sw, row, col, val); } else { update(node.se, row, col, val); } } node.sum = 0; if(node.nw != null) { node.sum += node.nw.sum; } if(node.ne != null) { node.sum += node.ne.sum; } if(node.sw != null) { node.sum += node.sw.sum; } if(node.se != null) { node.sum += node.se.sum; } } public int sumRegion(int row1, int col1, int row2, int col2) { return sumRegion(root, row1, col1, row2, col2); } private int sumRegion(SegmentTreeNode2D node, int tlRow, int tlCol, int brRow, int brCol) { if(node.tlRow == tlRow && node.tlCol == tlCol && node.brRow == brRow && node.brCol == brCol) { return node.sum; } int rowMid = node.tlRow + (node.brRow - node.tlRow) / 2; int colMid = node.tlCol + (node.brCol - node.tlCol) / 2; if(brRow <= rowMid) { // top-half plane if(brCol <= colMid) { // north-west quadrant return sumRegion(node.nw, tlRow, tlCol, brRow, brCol); } else if(tlCol > colMid) { // north-east quadrant return sumRegion(node.ne, tlRow, tlCol, brRow, brCol); } else { // intersection between nw and ne return sumRegion(node.nw, tlRow, tlCol, brRow, colMid) + sumRegion(node.ne, tlRow, colMid + 1, brRow, brCol); } } else if(tlRow > rowMid) { // bot-half plane if(brCol <= colMid) { // south-west quadrant return sumRegion(node.sw, tlRow, tlCol, brRow, brCol); } else if(tlCol > colMid) { // south-east quadrant return sumRegion(node.se, tlRow, tlCol, brRow, brCol); } else { //intersection between sw and sw return sumRegion(node.sw, tlRow, tlCol, brRow, colMid) + sumRegion(node.se, tlRow, colMid + 1, brRow, brCol); } } else { // full-plane intersection if(brCol <= colMid) { // left half plane return sumRegion(node.nw, tlRow, tlCol, rowMid, brCol) + sumRegion(node.sw, rowMid + 1, tlCol, brRow, brCol) ; } else if(tlCol > colMid) { // right half plane return sumRegion(node.ne, tlRow, tlCol, rowMid, brCol) + sumRegion(node.se, rowMid + 1, tlCol, brRow, brCol) ; } else { // full-plane intersection return sumRegion(node.nw, tlRow, tlCol, rowMid, colMid) + sumRegion(node.ne, tlRow, colMid + 1, rowMid, brCol) + sumRegion(node.sw, rowMid + 1, tlCol, brRow, colMid) + sumRegion(node.se, rowMid + 1, colMid + 1, brRow, brCol); } } } private SegmentTreeNode2D buildTree(int[][] matrix, int tlRow, int tlCol, int brRow, int brCol) { if(tlRow > brRow || tlCol > brCol) { return null; } else { SegmentTreeNode2D node = new SegmentTreeNode2D(tlRow, tlCol, brRow, brCol); if(tlRow == brRow && tlCol == brCol) { node.sum = matrix[tlRow][tlCol]; } else { int rowMid = tlRow + (brRow - tlRow) / 2; int colMid = tlCol + (brCol - tlCol) / 2; node.nw = buildTree(matrix, tlRow, tlCol, rowMid, colMid); node.ne = buildTree(matrix, tlRow, colMid + 1, rowMid, brCol); node.sw = buildTree(matrix, rowMid + 1, tlCol, brRow, colMid); node.se = buildTree(matrix, rowMid + 1, colMid + 1, brRow, brCol); node.sum = 0; if(node.nw != null) { node.sum += node.nw.sum; } if(node.ne != null) { node.sum += node.ne.sum; } if(node.sw != null) { node.sum += node.sw.sum; } if(node.se != null) { node.sum += node.se.sum; } } return node; } } } // Your NumMatrix object will be instantiated and called as such: // NumMatrix numMatrix = new NumMatrix(matrix); // numMatrix.sumRegion(0, 1, 2, 3); // numMatrix.update(1, 1, 10); // numMatrix.sumRegion(1, 2, 3, 4);
2D Fenwick Tree: -- 看了Quora一个acm大神的post之后,我决定仍是要使用2D Fenwick Tree来作这题。 “https://www.quora.com/How-does-a-2D-segment-tree-work” ,代码确定比Segment Tree简洁,并且速度也会更快。基本方法和1D很是相似,这种方法甚至能够简单地扩展到更高维度。google
Time Complexity - O(mnlogm * logn) build, O(logmn) update, O(logmn) rangeSum, Space Complexity - O(mn)
public class NumMatrix { private int BIT2D[][]; private int matrix[][]; public NumMatrix(int[][] matrix) { if(matrix == null || matrix.length == 0) { return; } BIT2D = new int[matrix.length + 1][matrix[0].length + 1]; this.matrix = new int[matrix.length][matrix[0].length]; for(int i = 0; i < matrix.length; i++) { for(int j = 0; j < matrix[0].length; j++) { update(i, j, matrix[i][j]); } } } public void update(int row, int col, int val) { int delta = val - matrix[row][col]; matrix[row][col] = val; for(int i = row + 1; i < BIT2D.length; i += i & (-i)) { //also equals to i |= i + 1 for(int j = col + 1; j < BIT2D[0].length; j += j & (-j)) { BIT2D[i][j] += delta; } } } public 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); } private int getSum(int row, int col) { int sum = 0; for(int i = row; i > 0; i -= i & (-i)) { for(int j = col; j > 0; j -= j & (-j)) { sum += BIT2D[i][j]; } } return sum; } } // Your NumMatrix object will be instantiated and called as such: // NumMatrix numMatrix = new NumMatrix(matrix); // numMatrix.sumRegion(0, 1, 2, 3); // numMatrix.update(1, 1, 10); // numMatrix.sumRegion(1, 2, 3, 4);
Reference:
https://stackoverflow.com/questions/25121878/2d-segment-quad-tree-explanation-with-c/25122078#25122078
https://sites.google.com/site/indy256/algo/fenwick_tree_2d
http://www.hawstein.com/posts/binary-indexed-trees.html
https://www.topcoder.com/community/data-science/data-science-tutorials/binary-indexed-trees/
http://www.wohenniu.com/thread-872-1-1.html
http://bookshadow.com/leetcode/
http://cs.nyu.edu/courses/spring14/CSCI-UA.0480-004/
https://web.stanford.edu/class/cs97si/03-data-structures.pdf
http://stackoverflow.com/questions/9452701/ukkonens-suffix-tree-algorithm-in-plain-english
https://leetcode.com/discuss/71025/segmentation-tree-736ms-indexed-tree-492ms-based-solutions
https://leetcode.com/discuss/70992/c-solution-using-2d-binary-index-tree-easy-to-understand
https://leetcode.com/discuss/72685/share-my-java-2-d-binary-indexed-tree-solution
https://leetcode.com/discuss/71046/java-2d-binary-indexed-tree-solution-80ms
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
https://leetcode.com/problems/range-sum-query-2d-mutable/
http://www.lxway.com/5152462.htm
https://www.topcoder.com/community/data-science/data-science-tutorials/binary-indexed-trees/