308. Range Sum Query 2D - Mutable

題目: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

Range Sum Query 2D
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

  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/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/

相關文章
相關標籤/搜索