308. Range Sum Query 2D - Mutable
题目:
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:
- The matrix is only modifiable by the update function.
- You may assume the number of calls to update and sumRegion function is distributed evenly.
- 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的更多相关文章
- LeetCode 308. Range Sum Query 2D - Mutable
原题链接在这里:https://leetcode.com/problems/range-sum-query-2d-mutable/ 题目: Given a 2D matrix matrix, find ...
- 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 ...
- [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 ...
- [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 ...
- 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 ...
- LeetCode Range Sum Query 2D - Mutable
原题链接在这里:https://leetcode.com/problems/range-sum-query-2d-mutable/ 题目: Given a 2D matrix matrix, find ...
- [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 ...
- [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 ...
- [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 ...
随机推荐
- 30道四则运算题目---课堂作业--软件工程c++
问题:设计一程序,给二年级小学生随机产生四则运算题目. 一.设计思考问题: 1.四则运算需要俩个运算数和一个运算符. 2.如何产生随机数? 3.如何实现随机产生四则运算? 4.题目是否符合小学生学习范 ...
- Object常用方法
1.clone() 创建并返回对象的一个副本,要进行“克隆”的对象所属的类必须实现java.lang.Cloneable接口 2.equals() 功能:比较引用数据类型的等价性 等价标准:引用类型比 ...
- 关于js with语句的一些理解
关于js with语句的一些理解 今天看到js的with语句部分,书中写到,with语句接收的对象会添加到作用域链的前端并在代码执行完之后移除.看到这里,我有两点疑问,添加到作用域链前端是不是指对 ...
- php编写验证码
今天学习到了php登录时的验证码,验证码在我们平时的网站建设中是非常重要的,对于放置一些灌水机.脚本攻击是一个很好地策略. 下面是我写的代码: <?php session_start(); // ...
- C#委托详解(1):什么是委托
本系列文章将详细探讨C#中的委托,列举其主要的实现方式,并分析其在设计层面和编码层面带来的好处,最后会讨论其安全性和执行效率等. 什么是委托? 委托是寻址方法的.NET版本,使用委托可以将方法作为参数 ...
- 用setTimeout 代替 setInterval实时拉取数据
在开发中,我们常常碰到需要定时拉取网站数据,如: setInterval(function(){ $.ajax({ url: 'xx', success: function( response ){ ...
- android 自动化压力测试-monkey 1 实践
Monkey是Android中的一个命令行工具,可以运行在模拟器里或实际设备中.它向系统发送伪随机的用户事件流(如按键输入.触摸屏输入.手势输入等),实现对正在开发的应用程序进行压力测试.Monkey ...
- 【BZOJ】【1042】【HAOI2008】硬币购物
DP+容斥原理 sigh……就差一点…… 四种硬币的数量限制就是四个条件,满足条件1的方案集合为A,满足条件2的方案集合为B……我们要求的就是同时满足四个条件的方案集合$A\bigcap B\bigc ...
- 项目分析 NGPcontext
NGPcontext 之前对这个一直很疑惑,我一直认为只是在机器人方面有用处,但很有疑问,正在做这方面,我想好好看看到底是怎么运行的 bool NGP::init(NGPcontext context ...
- 6-Highcharts曲线图之带标识
<!DOCTYPE> <html lang='en'> <head> <title>6-Highcharts曲线图之带标识</title> ...