I'm building a heatmap-like rectangular array interface and I want the 'hot' location to be at the top left of the array, and the 'cold' location to be at the bottom right. Therefore, I need an array to be filled diagonally like this:
0 1 2 3
|----|----|----|----|
0 | 0 | 2 | 5 | 8 |
|----|----|----|----|
1 | 1 | 4 | 7 | 10 |
|----|----|----|----|
2 | 3 | 6 | 9 | 11 |
|----|----|----|----|
So actually, I need a function f(x,y) such that
f(0,0) = 0
f(2,1) = 7
f(1,2) = 6
f(3,2) = 11
(or, of course, a similar function f(n) where f(7) = 10, f(9) = 6, etc.).
Finally, yes, I know this question is similar to the ones asked here, here and here, but the solutions described there only traverse and don't fill a matrix.
Interesting problem if you are limited to go through the array row by row.
I divided the rectangle in three regions. The top left triangle, the bottom right triangle and the rhomboid in the middle.
For the top left triangle the values in the first column (x=0) can be calculated using the common arithmetic series 1 + 2 + 3 + .. + n = n*(n+1)/2. Fields in the that triangle with the same x+y value are in the same diagonal and there value is that sum from the first colum + x.
The same approach works for the bottom right triangle. But instead of x and y, w-x and h-y is used, where w is the width and h the height of rectangle. That value have to be subtracted from the highest value w*h-1 in the array.
There are two cases for the rhomboid in the middle. If the width of rectangle is greater than (or equal to) the height, then the bottom left field of the rectangle is the field with the lowest value in the rhomboid and can be calculated that sum from before for h-1. From there on you can imagine that the rhomboid is a rectangle with a x-value of x+y and a y-value of y from the original rectangle. So calculations of the remaining values in that new rectangle are easy.
In the other case when the height is greater than the width, then the field at x=w-1 and y=0 can be calculated using that arithmetic sum and the rhomboid can be imagined as a rectangle with x-value x and y-value y-(w-x-1).
The code can be optimised by precalculating values for example. I think there also is one formula for all that cases. Maybe i think about it later.
inline static int diagonalvalue(int x, int y, int w, int h) {
if (h > x+y+1 && w > x+y+1) {
// top/left triangle
return ((x+y)*(x+y+1)/2) + x;
} else if (y+x >= h && y+x >= w) {
// bottom/right triangle
return w*h - (((w-x-1)+(h-y-1))*((w-x-1)+(h-y-1)+1)/2) - (w-x-1) - 1;
}
// rhomboid in the middle
if (w >= h) {
return (h*(h+1)/2) + ((x+y+1)-h)*h - y - 1;
}
return (w*(w+1)/2) + ((x+y)-w)*w + x;
}
for (y=0; y<h; y++) {
for (x=0; x<w; x++) {
array[x][y] = diagonalvalue(x,y,w,h);
}
}
Of course if there is not such a limitation, something like that should be way faster:
n = w*h;
x = 0;
y = 0;
for (i=0; i<n; i++) {
array[x][y] = i;
if (y <= 0 || x+1 >= w) {
y = x+y+1;
if (y >= h) {
x = (y-h)+1;
y -= x;
} else {
x = 0;
}
} else {
x++;
y--;
}
}
What about this (having an NxN matrix):
count = 1;
for( int k = 0; k < 2*N-1; ++k ) {
int max_i = std::min(k,N-1);
int min_i = std::max(0,k-N+1);
for( int i = max_i, j = min_i; i >= min_i; --i, ++j ) {
M.at(i).at(j) = count++;
}
}
Follow the steps in the 3rd example -- this gives the indexes (in order to print out the slices) -- and just set the value with an incrementing counter:
int x[3][3];
int n = 3;
int pos = 1;
for (int slice = 0; slice < 2 * n - 1; ++slice) {
int z = slice < n ? 0 : slice - n + 1;
for (int j = z; j <= slice - z; ++j)
x[j][slice - j] = pos++;
}
At a M*N matrix, the values, when traversing like in your stated example, seem to increase by n, except for border cases, so
f(0,0)=0
f(1,0)=f(0,0)+2
f(2,0)=f(1,0)+3
...and so on up to f(N,0). Then
f(0,1)=1
f(0,2)=3
and then
f(m,n)=f(m-1,n)+N, where m,n are index variables
and
f(M,N)=f(M-1,N)+2, where M,N are the last indexes of the matrix
This is not conclusive, but it should give you something to work with. Note, that you only need the value of the preceding element in each row and a few starting values to begin.
If you want a simple function, you could use a recursive definition.
H = height
def get_point(x,y)
if x == 0
if y == 0
return 0
else
return get_point(y-1,0)+1
end
else
return get_point(x-1,y) + H
end
end
This takes advantage of the fact that any value is H+the value of the item to its left. If the item is already at the leftmost column, then you find the cell that is to its far upper right diagonal, and move left from there, and add 1.
This is a good chance to use dynamic programming, and "cache" or memoize the functions you've already accomplished.
If you want something "strictly" done by f(n), you could use the relationship:
n = ( n % W , n / H ) [integer division, with no remainder/decimal]
And work your function from there.
Alternatively, if you want a purely array-populating-by-rows method, with no recursion, you could follow these rules:
If you are on the first cell of the row, "remember" the item in the cell (R-1) (where R is your current row) of the first row, and add 1 to it.
Otherwise, simply add H to the cell you last computed (ie, the cell to your left).
Psuedo-Code: (Assuming array is indexed by arr[row,column])
arr[0,0] = 0
for R from 0 to H
if R > 0
arr[R,0] = arr[0,R-1] + 1
end
for C from 1 to W
arr[R,C] = arr[R,C-1]
end
end
Related
Maximum Product.
The input to the problem is a string Z = z1,z2.....zn where each zi is any number between 1...9 and an integer k where 0 <= k < n.
An example string is Z = 8473817, which is of length n = 7. We want to insert k multiplication operators X into the string so that the mathematical result of the expression
is the largest possible. There are n - 1 possible locations for the operators,
namely, after the ith character where i = 1,....., n - 1.
For example, for input Z = 21322 and k = 2, then one possible way to insert the X operators
is: 2 X 1 X 322 = 644, another possibility is 21 X 3 X 22 = 1386.
Design a dynamic programming to output the maximum product
obtainable from inserting exactly k multiplication operators X into the string.
You can assume that all the multiplication operations in your algorithm take
O(1) time.
I am approaching this using the Matrix Chain Multiplication method where you compute smaller subproblem along the upper diagonal.
This works when K=1 i.e. one multiplication operator is inserted.
In the picture below, I have used 8473817 as an example and shown that 8473 X 817 yields the highest product.
How do I scale this solution for K > 1 and K < N.
Update: adding a pseudo code.
let A(i,j) store the max product for the strings A(i...j) 1 < i < j < n
for i = 1 -> n:
A(i,i) = Z(i)
for s = 1 -> n-1:
for i = 1 -> n-s:
j = i + s
A(i,j) = 0
for l = i -> j-1:
A(i,j) = max (A(i,j), A(i,l) * A(l+1,j)
return A(1,n)
The above code works when k = 1. How do I scale this up when k > 1 and less than n
Update
Based on #trincot solution, I revamped the soln to not use memoization
Sub problem Defn
Let T(i) store the start offset where inserting the X operator in Z yields max value for i : 1 < i < k.
Pseudo code
`
T(0) = 0
for i = 1 -> k:
max = 0
for j = T(i-1) + 1 -> n:
result = Z[1..j] * Z[j+1..n]
if result > max
max = result
T(i) = j
val = 1
for i = 1 -> k:
val = val * Z[T(i-1)+1...T(i)]
val = val * Z[T(k)+1..n]
Your pseudo code is a dynamic programming solution where you use memoization for every possible slice of z (2 dimensions, starting and ending offset). However, you would only need to memoize the best result for any suffix of z, so you would only need one (starting) offset. A second dimension in your memoization would then be used for the value of k (the number of remaining multiplications).
So you would still need a 2-dimensional table for memoization, but one index would be for k and the other for an offset in z.
Here is an implementation in JavaScript:
function solve(z, k) {
// Initialise a kxl array (where l is the length of z), filled with zeroes.
const memo = Array.from({length: k + 1}, () => Array(z.length + 1).fill(0));
function recur(z, k) {
if (k == 0) return z;
let result = memo[k][z.length];
if (result == 0) {
for (let i = 1; i <= z.length - k; i++) {
result = Math.max(result, +z.slice(0, i) * recur(z.slice(i), k - 1));
}
memo[k][z.length] = result;
}
return result;
}
return recur(z, k);
}
// A few example runs:
console.log(solve('8473817', 1)); // 6922441
console.log(solve('21322', 2)); // 1368
console.log(solve('191111', 2)); // 10101
Bottom up
The same can be done in an iterative algorithm -- bottom-up instead of top-down. Here we can save one dimension of the memoization array, as the same array can be re-used for the next value of k as it increases from 0 to its final value:
function solve(z, k) {
const memo = Array(z.length);
// Initialise for k=0:
// the best product in a suffix is the suffix itself
for (let i = 0; i < z.length; i++) {
memo[i] = +z.slice(i);
}
for (let kk = 1; kk <= k; kk++) {
for (let i = 0; i < z.length - kk; i++) {
// find best position for multiplication
let result = 0;
for (let j = i + 1; j < z.length - kk + 1; j++) {
result = Math.max(result, +z.slice(i, j) * memo[j]);
}
memo[i] = result;
}
}
return memo[0];
}
// A few example runs:
console.log(solve('8473817', 1)); // 6922441
console.log(solve('21322', 2)); // 1368
console.log(solve('191111', 2)); // 10101
(Code not supplied because this is homework.)
You have found that you can use the method once and get a solution for k=1.
Can you do it and find the best solution ending at every position in the string?
Now can you use the output of that second generalization and a similar method to get a complete solution for k=2?
Now can you write this a loop to solve for arbitrary k?
If you can do all that, then finishing is easy.
You have n-1 positions and k operators to insert. To me that looks like a binary number with n-1 bits including k 1's and the other positions set to 0.
Systematically generate all permutations of [0..01..1], insert multiplication operators at the 1 positions and calculate the result for each permutation.
Given an increasing sequence of N numbers (up to T), we can use at most K rectangles (placed starting at position 0) such as for the i-th value v in the sequence, exists a rectangle in positions [v, T) with height at least i + 1.
Total area of rectangles should be the minimum that satisfies what mentioned above.
Example: given the sequence [0, 3, 4], T = 5 and K = 2 we can use:
a rectangle from 0 to 2 with height 1 (thus having an area of 3)
a rectangle from 3 to 4 with height 3 (thus having an area of 6).
Using at most 2 rectangles, we cannot get a total area smaller than 9.
This problem can be solved using DP.
int dp[MAXK+1][MAXN][MAXN];
int sequence[MAXN];
int filldp(int cur_idx, int cur_value, int cur_K) {
int res = dp[cur_K][cur_idx][cur_value];
if (res != -1) return res;
res = INF;
if (cur_idx == N - 1 && cur_value >= N)
res = min(res, (T - seq[cur_idx]) * cur_value);
else {
if (cur_idx < N - 1 && cur_value >= cur_idx + 1) {
int cur_cost = (seq[cur_idx + 1] - seq[cur_idx]) * cur_value;
res = min(res, cur_cost + filldp(cur_idx + 1, cur_value, cur_K);
}
// Try every possible height for a rectangle
if (cur_K < K)
for (int new_value = cur_value + 1; cur_value <= N; new_value++)
res = min(res, filldp(cur_idx, new_value, cur_K + 1));
}
dp[cur_K][cur_idx][cur_value] = res;
return res;
}
Unsurprisingly, this DP approach is not really fast probably due to the for cycle. However, as far as I can understand, this code should not do more than MAXK * MAXN * MAXN significative calls (i.e., not more that every cell in dp). MAXK and MAXN are both 200, so dp has 8 millions of cells, which is not too much.
Am I missing anything?
UPDATE: As pointed out by Saeed Amiri (thank you!), the code makes N^2*K significative calls, but each one is O(N). The whole algorithm is then O(N^3*K) = O(N^4).
Can we do better?
I came across this in a recent interview.
We are given a N*M grid consisting of numbers and a path in the grid is the nodes you traverse.We are given a constraint that we can only move either right or down in the grid.So given this grid, we need to find the lexographically smallest path,after sorting it, to reach from top left to bottom right point of the grid
Eg. if grid is 2*2
4 3
5 1
then lexographically smallest path as per the question is "1 3 4".
How to do such problem? Code is appreciated. Thanks in advance.
You can use Dynamic programming to solve this problem. Let f(i, j) be the smallest lexicographical path (after sorting the path) from (i, j) to (N, M) moving only right and down. Consider the following recurrence:
f(i, j) = sort( a(i, j) + smallest(f(i + 1, j), f(i, j + 1)))
where a(i, j) is the value in the grid at (i, j), smallest (x, y) returns the smaller lexicographical string between x and y. the + concatenate two strings, and sort(str) sorts the string str in lexical order.
The base case of the recurrence is:
f(N, M) = a(N, M)
Also the recurrence change when i = N or j = M (make sure that you see that).
Consider the following code written in C++:
//-- the 200 is just the array size. It can be modified
string a[200][200]; //-- represent the input grid
string f[200][200]; //-- represent the array used for memoization
bool calculated[200][200]; //-- false if we have not calculate the value before, and true if we have
int N = 199, M = 199; //-- Number of rows, Number of columns
//-- sort the string str and return it
string srt(string &str){
sort(str.begin(), str.end());
return str;
}
//-- return the smallest of x and y
string smallest(string & x, string &y){
for (int i = 0; i < x.size(); i++){
if (x[i] < y[i]) return x;
if (x[i] > y[i]) return y;
}
return x;
}
string solve(int i, int j){
if (i == N && j == M) return a[i][j]; //-- if we have reached the buttom right cell (I assumed the array is 1-indexed
if (calculated[i][j]) return f[i][j]; //-- if we have calculated this before
string ans;
if (i == N) ans = srt(a[i][j] + solve(i, j + 1)); //-- if we are at the buttom boundary
else if (j == M) ans = srt(a[i][j] + solve(i + 1, j)); //-- if we are at the right boundary
else ans = srt(a[i][j] + smallest(solve(i, j + 1), solve(i + 1, j)));
calculated[i][j] = true; //-- to fetch the calculated result in future calls
f[i][j] = ans;
return ans;
}
string calculateSmallestPath(){
return solve(1, 1);
}
You can apply a dynamic programming approach to solve this problem in O(N * M * (N + M)) time and space complexity.
Below I'll consider, that N is the number of rows, M is the number of columns, and top left cell has coordinates (0, 0), first for row and second for column.
Lets for each cell store the lexicographically smallest path ended at this cell in sorted order. The answer for row and column with 0 index is trivial, because there is only one way to reach each of these cells. For the rest of cells you should choose the smallest path for top and left cells and insert the value of current cell.
The algorithm is:
path[0][0] <- a[0][0]
path[i][0] <- insert(a[i][0], path[i - 1][0])
path[0][j] <- insert(a[0][j], path[0][j - 1])
path[i][j] <- insert(a[i][j], min(path[i - 1][j], path[i][j - 1])
If no number is repeated, this can be achieved in O (NM log (NM)) as well.
Intuition:
Suppose I label a grid with upper left corner (a,b) and bottom right corner (c,d) as G(a,b,c,d). Since you've to attain the lexicographically smallest string AFTER sorting the path, the aim should be to find the minimum value every time in G. If this minimum value is attained at, let's say, (i,j), then G(i,b,c,j) and G(a,j,i,d) are rendered useless for the search of our next min (for the path). That is to say, the values for the path we desire would never be in these two grids. Proof? Any location within these grids, if traversed will not let us reach the minimum value in G(a,b,c,d) (the one at (i,j)). And, if we avoid (i,j), the path we build cannot be lexicographically smallest.
So, first we find the min for G(1,1,m,n). Suppose it's at (i,j). Mark the min. We then find out the min in G(1,1,i,j) and G(i,j,m,n) and do the same for them. Keep continuing this way until, at the end, we have m+n-1 marked entries, which will constitute our path. Traverse the original grid G(1,1,m,n) linearly and the report the value if it is marked.
Approach:
To find the min every time in G is costly. What if we map each value in the grid to it's location? - Traverse the grid and maintain a dictionary Dict with the key being the value at (i,j) and the value being the tuple (i,j). At the end, you'll have a list of key value pairs covering all the values in the grid.
Now, we'll be maintaining a list of valid grids in which we will find candidates for our path. The first valid grid will be G(1,1,m,n).
Sort the keys and start iterating from the first value in the sorted key set S.
Maintain a tree of valid grids, T(G), such that for each G(a,b,c,d) in T, G.left = G(a,b,i,j) and G.right = G(i,j,c,d) where (i,j) = location of min val in G(a,b,c,d)
The algorithm now:
for each val in sorted key set S do
(i,j) <- Dict(val)
Grid G <- Root(T)
do while (i,j) in G
if G has no child do
G.left <- G(a,b,i,j)
G.right <- G(i,j,c,d)
else if (i,j) in G.left
G <- G.left
else if (i,j) in G.right
G <- G.right
else
dict(val) <- null
end do
end if-else
end do
end for
for each val in G(1,1,m,n)
if dict(val) not null
solution.append(val)
end if
end for
return solution
The Java code:
class Grid{
int a, b, c, d;
Grid left, right;
Grid(int a, int b, int c, int d){
this.a = a;
this.b = b;
this.c = c;
this.d = d;
left = right = null;
}
public boolean isInGrid(int e, int f){
return (e >= a && e <= c && f >= b && f <= d);
}
public boolean hasNoChild(){
return (left == null && right == null);
}
}
public static int[] findPath(int[][] arr){
int row = arr.length;
int col = arr[0].length;
int[][] index = new int[row*col+1][2];
HashMap<Integer,Point> map = new HashMap<Integer,Point>();
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
map.put(arr[i][j], new Point(i,j));
}
}
Grid root = new Grid(0,0,row-1,col-1);
SortedSet<Integer> keys = new TreeSet<Integer>(map.keySet());
for(Integer entry : keys){
Grid temp = root;
int x = map.get(entry).x, y = map.get(entry).y;
while(temp.isInGrid(x, y)){
if(temp.hasNoChild()){
temp.left = new Grid(temp.a,temp.b,x, y);
temp.right = new Grid(x, y,temp.c,temp.d);
break;
}
if(temp.left.isInGrid(x, y)){
temp = temp.left;
}
else if(temp.right.isInGrid(x, y)){
temp = temp.right;
}
else{
map.get(entry).x = -1;
break;
}
}
}
int[] solution = new int[row+col-1];
int count = 0;
for(int i = 0 ; i < row; i++){
for(int j = 0; j < col; j++){
if(map.get(arr[i][j]).x >= 0){
solution[count++] = arr[i][j];
}
}
}
return solution;
}
The space complexity is constituted by maintenance of dictionary - O(NM) and of the tree - O(N+M). Overall: O(NM)
The time complexity for filling up and then sorting the dictionary - O(NM log(NM)); for checking the tree for each of the NM values - O(NM log(N+M)). Overall - O(NM log(NM)).
Of course, this won't work if values are repeated since then we'd have more than one (i,j)'s for a single value in the grid and the decision to chose which will no longer be satisfied by a greedy approach.
Additional FYI: The problem similar to this I heard about earlier had an additional grid property - there are no values repeating and the numbers are from 1 to NM. In such a case, the complexity could further reduce to O(NM log(N+M)) since instead of a dictionary, you can simply use values in the grid as indices of an array (which won't required sorting.)
I have a list of endpoints of possibly overlapping intervals, and I'd like an efficient way to compute the total area covered by k intervals, for k=1,2,... (without doing all pairwise comparisons). Or, is this not possible?
For example, suppose x is the list of start points, and y is the list of end points,
and that x[i] < y[i], and
x = (1.5, 2, 3, 5)
y = (3, 4, 4, 6)
so that the total area covered by at least one interval is 3.5, and the total area covered by at least two is 1.
thanks, ph.
This is a classic line sweep problem from computational geometry.
Put a +1 at each start point, and a -1 at every end point. Then imagine walking on the number line from negative infinity to positive infinity.
Every time you encounter a +1, increment your height by 1. Everytime you hit a -1, decrease your height. As you move from p1 to p2 on the number line, add p2 - p1 (length swept) to the amount covered by the given height.
Then you'll have a histogram of lengths covered by exactly by each height. You can accumulate the totals if you want to handle the "at least two intervals" case.
I didn't know #rrenaud had posted his solution while I was writing the same thing, so I'll omit the explanation and just give you the code. This is a javascript version of line sweep:
// x and y inputs are your start and end points for ranges,
// as in the example data
function countOverlapRanges(x, y) {
var ranges = [];
var n = x.length;
if (n !== y.length) {
throw "Input arrays must be the same length!";
}
var i;
// iterate over all inputs, pushing them into the array
for (i = 0; i < n; ++i) {
ranges.push({
value: x[i],
change: 1
});
ranges.push({
value: y[i],
change: -1
});
}
// sort the array into number-line order
ranges.sort(function (a, b) {
return a.value - b.value;
});
var result = {};
var k = 1;
var maxK = 1;
n = ranges.length;
// iterate over the sorted data, counting the size of ranges
var cur, value, lastValue = ranges[0].value;
for (i = 1; i < n; ++i) {
cur = ranges[i];
value = cur.value;
if (k) {
var difference = value - lastValue;
result[k] = (result[k] || 0) + difference;
}
k += cur.change;
maxK = Math.max(maxK, k);
lastValue = value;
}
// so far we've counted the ranges covered by exactly k intervals.
// adjust the results to get the size of ranges covered by
// at least k intervals.
var sum = 0;
for (i = maxK; i > 0; --i) {
sum = result[i] = sum + result[i];
}
return result;
}
It returns an object that maps k values to distances along the line.
In an interview I was asked if I was given an n*m matrix how to calculate the sum of the values in a given sub-matrix (defined by top-left, bottom-right coordinates).
I was told I could pre-process the matrix.
I was told the matrix could be massive and so could the sub-matrix so the algo had to be efficient. I stumbled a bit and wasn't told the best answer.
Anyone have a good answer?
This is what Summed Area Tables are for. http://en.wikipedia.org/wiki/Summed_area_table
Your "preprocessing" step is to build a new matrix of the same size, where each entry is the sum of the sub-matrix to the upper-left of that entry. Any arbitrary sub-matrix sum can be calculated by looking up and mixing only 4 entries in the SAT.
EDIT: Here's an example.
For the initial matrix
0 1 4
2 3 2
1 2 7
The SAT is
0 1 5
2 6 12
3 9 22
The SAT is obtained using S(x,y) = a(x,y) + S(x-1,y) + S(x,y-1) - S(x-1,y-1),
where S is the SAT matrix and a is the initial matrix .
If you want the sum of the lower-right 2x2 sub-matrix, the answer would be 22 + 0 - 3 - 5 = 14. Which is obviously the same as 3 + 2 + 2 + 7. Regardless of the size of the matrix, the sum of a sub matrix can be found in 4 lookups and 3 arithmetic ops. Building the SAT is O(n), similarly requiring only 4 lookups and 3 math ops per cell.
You can do it by Dynamic programming. Create matrix dp with size n*m.
And for each i, j where
1 <= i <= n , 1 <= j <= m
dp[i][j] will be :
dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + values[i][j]
And for each query we have lx, rx, ly, ry where lx and rx are top-left coordinates, ly and ry bottom-right coordinates of sub-matrix.
1 ≤ lxi ≤ rx ≤ n, 1 ≤ ly ≤ ry ≤ m
sum = dp[rx][ry] - dp[lx - 1][ry] - dp[rx][ly - 1] + dp[lx-1][ly - 1]
Look at picture to understand how algorithm works.
OD = dp[rx][ry], OB = dp[lx - 1][ry], OC = dp[rx][ly - 1], OA = dp[lx - 1][ly - 1]
Create a new matrix where entry (i,j) is the sum of elements in the original matrix that have lower or equal i and j. Then, to find the sum of the elements in the submatrix, you can just use a constant number of basic operations using the corners of the submatrix of your sum matrix.
In particular, find the corners top_left, bottom_left, top_right and bottom_right of your sum matrix, where the first three are just outside the submatrix and bottom_right is just inside. Then, your sum will be
bottom_right + top_left - bottom_left - bottom_right
Below is a sample implementation in C using Summed Area Tables concept as explained in one of the answers above.
Python implementation for the same can be found at below link -
http://www.ardendertat.com/2011/09/20/programming-interview-questions-2-matrix-region-sum/
#include<stdio.h>
int pre[3][3];
int arr[3][3] = {
{0,1,4},
{2,3,2},
{1,2,7}
};
void preprocess()
{
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
if(i>0 && j>0)
{
pre[i][j] = arr[i][j] + pre[i-1][j] + pre[i][j-1] - pre[i-1][j-1];
}
else if(i>0 && j==0)
{
pre[i][j] = arr[i][j] + pre[i-1][j];
}
else if(j>0 && i==0)
{
pre[i][j] = arr[i][j] + pre[i][j-1];
}
else
{
pre[i][j] = arr[i][j];
}
}
}
}
int subsum(int x1, int y1, int x2, int y2)
{
preprocess();
int ans = pre[x2][y2] - pre[x1-1][y2] - pre[x2][y1-1] + pre[x1-1][y1-1];
return ans;
}
int main()
{
printf("%d\n",subsum(1,1,2,2));
return 0;
}
This should work. You always have to go through each element in the submatrix to do the addition and this is the simplest way.
*note that the following code may not compile but it's right in pseudocode
struct Coords{
int x,y;
}
int SumSubMatrix(Coords topleft, Coords bottomright, int** matrix){
int localsum = 0;
for( int i = topleft.x; i <= bottomright.x; i++ ){
for(int j = topleft.y; j <= bottomright.y; j++){
localsum += matrix[i][j];
}
}
return localsum;
}
Edit: An alternative pre-processing method is to create another matrix from the original containing the row or column sums. Here's an example:
Original:
0 1 4
2 3 2
1 2 7
Row Matrix:
0 1 5
2 5 7
1 3 10
Column Matrix:
0 1 4
2 4 6
3 6 13
Now, just take the endpoint x values and subtract the start point values, like so (for rows based):
for( int i = topleft.y; i >= bottomright.y; i++ ){
localsum += matrix2[bottomright.x][i] - matrix2[topleft.x][i];
}
Now, it's either O( n ) or O( m )