题目:

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).


The above rectangle (with the red border) is defined by (row1, col1) = (2, 1) and (row2, col2) = (4, 3), which contains sum = 8.

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:

  1. The matrix is only modifiable by the update function.
  2. You may assume the number of calls to update and sumRegion function is distributed evenly.
  3. You may assume that row1 ≤ row2 and col1 ≤ col2.

链接: http://leetcode.com/problems/range-sum-query-2d-mutable/

题解:

二维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时的判断,有好几种情况,比较复杂。

2D Segment Tree: Time Complexity - O(mn) build,O(logmn) update, O(logmn) rangeSum , Space Complexity - O(mn)  复杂度算得不是很清楚,很可能不正确,二刷再继续改正。

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非常类似,这种方法甚至可以简单地扩展到更高维度。

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/

308. Range Sum Query 2D - Mutable的更多相关文章

  1. LeetCode 308. Range Sum Query 2D - Mutable

    原题链接在这里:https://leetcode.com/problems/range-sum-query-2d-mutable/ 题目: Given a 2D matrix matrix, find ...

  2. Range Sum Query 2D - Mutable & Immutable

    Range Sum Query 2D - Mutable Given a 2D matrix matrix, find the sum of the elements inside the recta ...

  3. [Locked] Range Sum Query 2D - Mutable

    Range Sum Query 2D - Mutable Given a 2D matrix matrix, find the sum of the elements inside the recta ...

  4. [LeetCode] Range Sum Query 2D - Mutable 二维区域和检索 - 可变

    Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper lef ...

  5. Leetcode: Range Sum Query 2D - Mutable && Summary: Binary Indexed Tree

    Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper lef ...

  6. LeetCode Range Sum Query 2D - Mutable

    原题链接在这里:https://leetcode.com/problems/range-sum-query-2d-mutable/ 题目: Given a 2D matrix matrix, find ...

  7. [Swift]LeetCode308. 二维区域和检索 - 可变 $ Range Sum Query 2D - Mutable

    Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper lef ...

  8. [LeetCode] Range Sum Query 2D - Immutable 二维区域和检索 - 不可变

    Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper lef ...

  9. [LeetCode] Range Sum Query - Immutable & Range Sum Query 2D - Immutable

    Range Sum Query - Immutable Given an integer array nums, find the sum of the elements between indice ...

随机推荐

  1. Implementation Documentation[转]

    原文地址:http://prasanna-adf.blogspot.tw/2009/04/implementation-documentation.html Following are the lis ...

  2. 关于js with语句的一些理解

    关于js with语句的一些理解   今天看到js的with语句部分,书中写到,with语句接收的对象会添加到作用域链的前端并在代码执行完之后移除.看到这里,我有两点疑问,添加到作用域链前端是不是指对 ...

  3. Extjs中TextField中显示图标

    现看实现效果:   实现代码: { width:500, height : 25, fieldLabel : '过滤条件', itemId : 'queryText', labelAlign : 'r ...

  4. 求字符串的最长回文字串 O(n)

    昨天参加了某公司的校园招聘的笔试题,做得惨不忍睹,其中就有这么一道算法设计题:求一个字符串的最长回文字串.我在ACM校队选拔赛上遇到过这道题,当时用的后缀数组AC的,但是模板忘了没写出代码来. 回头我 ...

  5. Application, JDBC, 数据库连接池, Session, 数据库的关系

    RT,这几个东东已经困扰我很长一段时间了... 这次争取把她们理清楚了! 参考资料: 1. 数据库连接池:http://www.cnblogs.com/shipengzhi/archive/2011/ ...

  6. 全球SEO行业调查报告

    这是一份来自MOZ的调查报告,本报告是两年一次的SEO行业调查,主要围绕SEO从业人员的特征.工作内容时间分配比例.对未来市场的看法.使用的seo工具以及SEO知识扩充渠道等展开. 这份报告可以对从事 ...

  7. Codeforces Round #268 (Div. 2)

    补题解: E:只会第四种解法:也只看懂了这一种. PS:F[X+10^18]=F[X]+1;F[X]表示X的数字之和; 假设X,F[10^18+X]+F[10^18+X-1]+......F[10^1 ...

  8. 利用Linq + Jquery + Ajax 异步分页的实现

    在Web显示的时候我们经常会遇到分页显示,而网上的分页方法甚多,但都太过于消耗带宽,所以我想到了用Ajax来分页,利用返回的Json来处理返回的数据, 大大简化了带宽的压力. 先说下思路,无非就是异步 ...

  9. POJ 2549

    Sumsets Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8235   Accepted: 2260 Descripti ...

  10. python 安装 管理包 pip

    2.7的坑里出不来了,现在已经换到3.4了,不存在下列问题. win7下安装pip    http://blog.chinaunix.net/uid-24984661-id-4202194.html ...