题目:

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. C语言中链表节点的实现,以及如何实现泛型

    1.C语言中的struct是纯粹的结构体,没有访问权限的概念 2.C语言中用void* 来实现泛型编程,也是C++类和模板底层实现的基础,就是用void*来实现的 #include<stdio. ...

  2. C++编程显示四则运算题目

    题目:C++编程显示四则运算题目 设计思路:(1)让用户自己确定出题的数量,同时显示加减乘除四则运算. (2)考虑到用户可能只会一种运算,因此可以选择运算.

  3. scala伴生对象,apply()及单例

    1:伴生对象与apply方法 如果一个class与一个object具有相同的名字,那么我们就认为它们互为伴生.object为class的伴生对象.如下图所示,object Apply为class Ap ...

  4. Tomcat性能参数设置

    Tomcat性能参数设置 Tomcat性能参数设置 博客分类: Java LinuxTomcat网络应用多线程Socket 默认参数不适合生产环境使用,因此需要修改一些参数 1.修改启动时内存参数.并 ...

  5. OS X 使用技巧——轻松地调整窗口大小

    如果你想调整窗口大小,只需要把鼠标指针悬停在窗口边框上.当它变成双向箭头时,点击并拖动鼠标即可完成这一操作. 但在实际操作中,迅速把鼠标指针定位到边框上比较困难. 解决的办法是:在终端输入以下命令: ...

  6. angular 嵌套实现树结构 ng-repeat ng-include

    效果图 ang.html <!doctype html><html lang="en"><head>    <meta charset=& ...

  7. Linux嵌入式系统与硬件平台的关系

    一. Linux嵌入式系统 操作系统是一种在计算机上运行的软件,它的主要任务是管理计算机上的系统资源,为用户提供使用计算机及其外部设备的接口.它存在的目的是为了管理所有硬件资源,并且提供应用软件一个合 ...

  8. [REFERENCE] Real-Time-Normal-Map-Dxt-Compression

    DXT5N & 3Dc(aka BC5) compression in common code & SIMD: http://mrelusive.com/publications/pa ...

  9. 在线编辑器 (UBB, FCK)

    这里主要说明一下:UBB UBB 使用类型HTML的语法.  UBB相对FCK的HTML方式, 安全性高. 用户不可以直接嵌入HTML代码.   UBB 在线编辑器(JS版): http://www. ...

  10. Sqli-labs less 38

    Less-38 学习了关于stacked injection的相关知识,我们在本关可以得到直接的运用. 在执行select时的sql语句为:SELECT * FROM users WHERE id=' ...