304 Range Sum Query 2D - Immutable

Given a 2D matrixmatrix, find the sum of the elements inside the rectangle defined by its upper left corner (row1,col1) and lower right corner (row2,col2).

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
sumRegion(1, 1, 2, 2) -
>
 11
sumRegion(1, 2, 2, 4) -
>
 12

Complexity: Linear to the number of elements n, in both time and space.

The Idea: We begin by building what is a called an integral matrix. An integral matrix uses the same principles as an integral array , but just expanded to 2 dimensions. An integral array is just the accumulative summation of elements within the array. For example:

Using this array, the idea is that now we can represent any cumulative subset of the array in O(1) time. Intuitively, this mean taking every accumulated to the end point, and subtracting it with the access we don't care about.

Using the same principles, we can generalize this to 2 dimensions.

Then a summation would look like this. Notice we are subtracting the upper corner twice, so we have to add it back in, just in set theory where (A or B) = A + B - (A and B)

class NumMatrix {
public:
    NumMatrix(vector<vector<int>> matrix)
        : matrix(matrix) {

        if (!matrix.empty()) {
            rowSize = matrix.size();
            colSize = matrix.at(0).size();

            integralMatrix.resize(rowSize);
            for (auto &i : integralMatrix) i.resize(colSize);

            computeIntegralMatrix();
        }
    }

    int sumRegion(int row1, int col1, int row2, int col2)
    {
        if (matrix.empty()) return 0;

        int bottom_right = integralMatrix[row2][col2];
        int bottom_left = isValid(row2, col1 - 1) ? integralMatrix[row2][col1 - 1] : 0;
        int top_right = isValid(row1 - 1, col2) ? integralMatrix[row1 - 1][col2] : 0;
        int diagonal = isValid(row1 - 1, col1 - 1) ? integralMatrix[row1 - 1][col1 - 1] : 0;

        return bottom_right - bottom_left - top_right + diagonal;
        cout << ' ';
    }

private:

    size_t rowSize, colSize;

    void computeIntegralMatrix()
    {
        for (int i = 0; i < rowSize; i++) {
            for (int j = 0; j < colSize; j++) {
                int top = isValid(i - 1, j) ? integralMatrix[i - 1][j] : 0;
                int left = isValid(i, j - 1) ? integralMatrix[i][j - 1] : 0;
                int diagonal = isValid(i - 1, j - 1) ? integralMatrix[i - 1][j - 1] : 0;
                integralMatrix[i][j] = top + left - diagonal + matrix[i][j];
            }
        }
    }

    bool isValid(const int &row, const int &col) {
        return (row >= 0 && col >= 0 && row < rowSize && col < colSize);
    }

    vector<vector<int>> matrix;
    vector<vector<int>> integralMatrix;
};

/**
* Your NumMatrix object will be instantiated and called as such:
* NumMatrix obj = new NumMatrix(matrix);
* int param_1 = obj.sumRegion(row1,col1,row2,col2);
*/

Some Testing:

int main()
{
    vector<vector<int>> matrix1 = {
        {1,2,3},
        {4,5,6},
        {7,8,9}
    };
    NumMatrix obj = NumMatrix(matrix1);
    assert(obj.sumRegion(1, 1, 2, 2) == 28);
    assert(obj.sumRegion(0, 0, 1, 1) == 12);
    assert(obj.sumRegion(0, 0, 0, 0) == 1);
    assert(obj.sumRegion(0, 1, 0, 1) == 2);

    vector<vector<int>> matrix2 = { { -5208,1041,-93779,-64152,17850,29055,-63731,-23568,41170,58457,-39616,55683,-51662,-75015,21726 },{ 4535,-72412,86878,-60825,67088,48794,-23471,-22403,58200,-31153,-94668,-27274,-11003,33894,-66125 },{ -9538,-33861,54822,42636,48430,-56030,-33348,-30617,5219,56501,-95879,-73537,-18157,-72815,-40977 },{ 15602,40115,-32475,99011,47251,84035,83793,-74389,-99042,65460,11671,-95294,68311,47893,71866 },{ 69607,57288,55022,36610,-75113,31344,34319,-13381,-74800,-71904,-15625,-5398,-29689,-68805,-41994 },{ -32276,95017,-96452,-47311,13238,46324,95358,13247,-30930,5815,-36748,-25712,-83982,29391,-73922 },{ -29140,-70403,-3168,12219,-4473,-10013,-85502,87222,-44858,66506,-99821,-16992,-80758,59210,87145 },{ -9557,67725,-27359,-28647,46781,-67948,-28154,-3498,91489,-3887,-96422,6568,42380,73264,-55406 },{ 40555,70153,-51490,-14237,9684,-54000,-8443,-32063,-96157,-70083,-7050,56221,93013,-1157,-45593 },{ -28686,-54296,628,11189,18227,-64455,-10528,-69244,94796,-39806,69194,45024,-14417,-51291,6387 },{ -28485,36898,97259,-83875,83650,-36715,80692,-55055,40025,-69379,-1548,-13045,23318,79349,-42774 },{ 82645,17721,84052,-35036,-751,90269,-77187,51972,-90217,-5956,-34552,95560,40436,51650,72778 },{ -970,77788,10423,-1406,-90844,6732,-60197,59393,-82111,33737,-4731,-52679,-12011,69741,-91931 } };
    NumMatrix obj2 = NumMatrix(matrix2);

    cout << obj2.sumRegion(3, 2, 12, 6) << endl;
    cout << obj2.sumRegion(11, 10, 11, 12) << endl;
    cout << obj2.sumRegion(7, 7, 7, 10) << endl;
    cout << obj2.sumRegion(7, 10, 10, 13) << endl;
    cout << obj2.sumRegion(2, 11, 5, 12) << endl;
    cout << obj2.sumRegion(10, 8, 10, 12) << endl;
    cout << obj2.sumRegion(12, 7, 12, 10) << endl;
    cout << obj2.sumRegion(1, 14, 9, 14) << endl;
    cout << obj2.sumRegion(11, 11, 11, 13) << endl;
    cout << obj2.sumRegion(7, 7, 9, 10) << endl;
    cout << obj2.sumRegion(12, 8, 12, 12) << endl;
    cout << obj2.sumRegion(1, 4, 6, 11) << endl;
    cout << obj2.sumRegion(0, 9, 9, 13) << endl;
    cout << obj2.sumRegion(9, 6, 9, 13) << endl;
    cout << obj2.sumRegion(10, 14, 11, 14) << endl;
    cout << obj2.sumRegion(4, 9, 7, 14) << endl;
    cout << obj2.sumRegion(5, 13, 7, 14) << endl;
    cout << obj2.sumRegion(12, 0, 12, 14) << endl;
    cout << obj2.sumRegion(9, 14, 11, 14) << endl;
    cout << obj2.sumRegion(2, 8, 10, 13) << endl;
    cout << obj2.sumRegion(3, 5, 12, 8) << endl;
    cout << obj2.sumRegion(5, 3, 11, 10) << endl;
    cout << obj2.sumRegion(1, 14, 11, 14) << endl;
    cout << obj2.sumRegion(8, 2, 11, 6) << endl;
    cout << obj2.sumRegion(3, 13, 12, 14) << endl;
    cout << obj2.sumRegion(4, 9, 11, 12) << endl;
    cout << obj2.sumRegion(7, 1, 9, 2) << endl;
    cout << obj2.sumRegion(0, 0, 8, 14) << endl;
    cout << obj2.sumRegion(11, 8, 12, 10) << endl;
    cout << obj2.sumRegion(1, 1, 10, 13) << endl;
}

Last updated