How to find minimum or maximum element in a matrix region? - algorithm

For NxM matrix with integer values, what is the most efficient way to find minimum element for region (x1,y1) (x2,y2) where 0 <= x1<=x2 < M and 0 <= y1 <= y2 < N
We can assume that we will query different regions numerous times.
I am wondering if we can extend range minumum query methods to this question.
http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=lowestCommonAncestor
Pretty straightforward solution could be use the most efficient solution of RMQ (Segment Tree) then apply it row or column wise.
Worst case complexity would be min(N,M)*log(max(N,M))
But still I believe we can do better than that.

It depends on what do you mean by "the most efficient way". It is possible to minimize query time itself, or preprocessing time, or memory requirements.
If only query time should be minimized, "the most efficient way" is to pre-compute all possible regions. Then each query is handled by returning some pre-computed value. Query time is O(1). Both memory and preprocessing time are huge: O((NM)2).
More practical is to use Sparse Table algorithm from the page referred in OP. This algorithm prepares a table of all power-of-two length intervals and uses a pair of these intervals to handle any range-minimum-query. Query time is O(1). Memory and preprocessing time are O(N log N). And this algorithm can be easily extended to two-dimensional case.
Just prepare a table of all power-of-two length and power-of-two height rectangles and use four of these rectangles to handle any range-minimum-query. The result is just a minimum of four minimum values for each of these rectangles. Query time is O(1). Memory and preprocessing time are O(NM*log(N)*log(M)).
This paper: "Two-Dimensional Range Minimum Queries" by Amihood Amir, Johannes Fischer, and Moshe Lewenstein suggests how to decrease memory requirements and preprocessing time for this algorithm to almost O(MN).
This paper: "Data Structures for Range Minimum Queries in Multidimensional Arrays" by Hao Yuan and Mikhail J. Atallah gives different algorithm with O(1) query time and O(NM) memory and preprocessing time.

Given no other information about the contents of the matrix or about the way it's stored, it's impossible to make any suggestion besides just scanning every entry in the given region. That's O((x2-x1) * (y2-y1)). Your question is too vague to state anything else.
You could perhaps do better (probabilistically, in the average case) if you knew something else about the matrix, for example if you know that the elements are probably sorted in some way.

Pseudocode:
function getMax(M, x1, x2, y1, y2)
max = M[x1,y1]
for x = x1 to x2 do
for y = y1 to y2 do
if M[x,y] > max then max = M[x, y]
return max
This is O(n) in the input size, which can only reasonable be interpreted as the size of the matrix region (x2 - x1) * (y2 - y1). If you want the minimum, change max to min and > to <. You cannot do better than O(n), i.e., checking each of the possible elements. Assume you had an algorithm that was faster than O(n). Then it doesn't check all elements. To get a failing case for the algorithm, take one of the elements it doesn't check, and replace it with (max + 1), and re-run the algorithm.

Related

Algorithm for finding all combinations of (x,y,z,j) that satisfy w+x = y+j, where w,x,y,j are integers between -N...N inclusive

I'm working on a problem that requires an array (dA[j], j=-N..N) to be calculated from the values of another array (A[i], i=-N..N) based on a conservation of momentum rule (x+y=z+j). This means that for a given index j for all the valid combinations of (x,y,z) I calculate A[x]A[y]A[z]. dA[j] is equal to the sum of these values.
I'm currently precomputing the valid indices for each dA[j] by looping x=-N...+N,y=-N...+N and calculating z=x+y-j and storing the indices if abs(z) <= N.
Is there a more efficient method of computing this?
The reason I ask is that in future I'd like to also be able to efficiently find for each dA[j] all the terms that have a specific A[i]. Essentially to be able to compute the Jacobian of dA[j] with respect to dA[i].
Update
For the sake of completeness I figured out a way of doing this without any if statements: if you parametrize the equation x+y=z+j given that j is a constant you get the equation for a plane. The constraint that x,y,z need to be integers between -N..N create boundaries on this plane. The points that define this boundary are functions of N and j. So all you have to do is loop over your parametrized variables (s,t) within these boundaries and you'll generate all the valid points by using the vectors defined by the plane (s*u + t*v + j*[0,0,1]).
For example, if you choose u=[1,0,-1] and v=[0,1,1] all the valid solutions for every value of j are bounded by a 6 sided polygon with points (-N,-N),(-N,-j),(j,N),(N,N),(N,-j), and (j,-N).
So for each j, you go through all (2N)^2 combinations to find the correct x's and y's such that x+y= z+j; the running time of your application (per j) is O(N^2). I don't think your current idea is bad (and after playing with some pseudocode for this, I couldn't improve it significantly). I would like to note that once you've picked a j and a z, there is at most 2N choices for x's and y's. So overall, the best algorithm would still complete in O(N^2).
But consider the following improvement by a factor of 2 (for the overall program, not per j): if z+j= x+y, then (-z)+(-j)= (-x)+(-y) also.

Finding the minimum element in a given range greater than a given number

We are given N (N <= 106) points on a 2D plane and an integer D (N <= 106), we want to find two points p1,p2 (p2 to the right of p1) such that the difference between p1.y and p2.y is at least D and p2.x - p1.x is minimized.
The x and y axis are in the range 0..106
This is a problem from a USACO past contest.
Here is my attempt to solve it:
MAXY = The maximum y axis among the N points.
Suppose we know p1, then we can find p2 quite easily; by taking all the points which have their y-axis in the range p1.y+D to MAXY or in the range 0 to p1.y-D and take the point which has the smallest x-axis greater than p.x. This will be the best choice for p2.
But as we don't know p1, we will have to try all points for p1 and so finding the best choice for p2 should be done efficiently.
I used a segment tree for that. Every node in the tree will store all the points in the corresponding range in sorted order of x-axis. While querying, if a node falls in the query range then we binary search on the array for p1.x and return the smallest element greater than it.
For every choice of p1, we query the tree twice with the ranges 0,p1.y-D and p1.y+D,MAXY and take the best of the two points returned.
The building of the tree can be done in O(NlogN) time.
Every query will take O(logN*logN) time, and we make N queries, so the total time taken is (Nlogn*logn) which might not run within the time limits of 2 seconds. (106*20*20).
Also the memory taken will be O(NlogN) which is about 80 mb (100000*20*4 kb) which is too much as the limit is 64 mb.
How can we do the queries faster and using lesser space?
It can be done much easier.
Suppose you have two copies of the array: one sorted by Y-axis and another by X-axis. Now you'll iterate through the Y-sorted array and for each point (let name it cur) you should binary search an appropriate point (with the smallest p2.x - p1.x) in the X-sorted array. In case of binary search will find the same point or the point with Y-coordinate less than cur+D you should just delete that point from X-sorted array (we'll never need that point in X-sorted array again because we only increase Y-coordinate) and run binary search again. The answer will be the smallest of the binary search results.
As we need fast timing we should erase points from array quickly. It can be done by using binary tree - it can erase any node in O(logN) time and can do binary search in O(logN) time. As you delete each node from the tree only once and it takes O(logN + logN) time - total time will be O(N * logN). Preprocesssing time is O(N * logN) too. Also the memory taken will be O(N).
By the way your solution is also appropriate because actual N is 10^5 not 10^6. Which allows your solution to keep timing below 2 seconds, and to use less than 20MB of memory.
How about just do Sort & Scan.
Sort by x since you want to find the minimum difference by x. It take O(N logN) time and in place.
Maintain two index i and j from the head of x.
The faster goes first, find the position of |P[i].y - P[j].y| > D
and the X = |P[i].x - P[j].x| is your first available choice.
Then updating X by moving the to index forward. Try P[i+1], scan from P[i+2] as P[j] and increase until |P[i].x - P[j].x| >= X. If there is an available new X, set this as X.
This might make do lot of compare at first. But since you updating your X, somehow will make your compare range shrinking.

Mapping functions to reduce Time Complexity? PhD Qual Item

This was on my last comp stat qual. I gave an answer I thought was pretty good. We just get our score on the exam, not whether we got specific questions right. Hoping the community can give guidance on this one, I am not interested in the answer so much as what is being tested and where I can go read more about it and get some practice before the next exam.
At first glance it looks like a time complexity question, but when it starts talking about mapping-functions and pre-sorting data, I am not sure how to handle.
So how would you answer?
Here it is:
Given a set of items X = {x1, x2, ..., xn} drawn from some domain Z, your task is to find if a query item q in Z occurs in the set. For simplicity you may assume each item occurs exactly once in X and that it takes O(l) amount of time to compare any two items in Z.
(a) Write pseudo-code for an algorithm which checks if q in X. What is the worst case time complexity of your algorithm?
(b) If l is very large (e.g. if each element of X is a long video) then one needs efficient algorithms to check if q \in X. Suppose you are given access to k functions h_i: Z -> {1, 2, ..., m} which uniformly map an element of Z to a number between 1 and m, and let k << l and m > n.
Write pseudo-code for an algorithm which uses the function h_1...h_k to check if q \in X. Note that you are allowed to preprocess the data. What is the worst case time complexity of your algorithm?
Be explicit about the inputs, outputs, and assumptions in your pseudocode.
The first seems to be a simple linear scan. The time complexity is O(n * l), the worst case is to compare all elements. Note - it cannot be sub-linear with n, since there is no information if the data is sorted.
The second (b) is actually a variation of bloom-filter, which is a probabalistic way to represent a set. Using bloom filters - you might have false positives (say something is in the set while it is not), but never false negative (say something is not int the set, while it is).

Find groups of contiguous cells in a 3D binary matrix

I want to find groups of contiguous cells in a matrix.
So for example let’s consider a 2D matrix below.
In the given matrix there are 2 contiguous groups of cells with value 1:
Here is one way to find these groups:
Assign 1st cell with value 1 a different value: let’s say A. Then examine cells with value 1 which are adjacent to A and set the value in those cells as A. Search this way until no more contiguous cells are found.
In the next step increment A to B and start with a cell having value 1. Then follow the same steps as above.
This is kind of brute force and it won’t be efficient in 3D. Does anyone know of any algorithm that I could use with a little tweaking?
Or any easy solution to this problem?
What you are trying to do goes, often, under the label connected component labelling. I won't elaborate further, the Wikipedia article explains matters better than I could or would.
But while I'm answering ...
You, and many others on SO, seem to think that simple iteration over all the elements of an array, which you characterise by the derogatory term brute-force, is something to be avoided at all costs. Modern computers are very, very fast. Accessing each element of an array in order is something that most compilers can optimise the hell out of.
You seem to have fallen into the trap of thinking that accessing every element of a 3D array has time-complexity in O(n^3), where n is the number of elements along each dimension of the array. It isn't: accessing elements of an array is in O(n) where n is the number of elements in the array.
Even if the time complexity of visiting each element in the array were in O(n^3) many sophisticated algorithms which offer better asymptotic time complexity, will prove, in practice, to deliver worse performance than the simpler algorithm. Many sophisticated algorithms make it much harder for the compiler to optimise code. And, bear in mind, that O(n^2) is an equivalence class of algorithms which includes algorithms with true time complexities such as O(m+k*n^2) where both of m and k are constants
Here is some psuedo code for a simple flood fill algorithm:
>>> def flood(i, j, matrix):
... if 0 <= i < len(matrix) and 0 <= j < len(matrix):
... if matrix[i][j] == 1:
... matrix[i][j] = 0
... for dx, dy in ((-1, 0), (1, 0), (0, -1), (0, 1)):
... flood(i + dx, j + dy, matrix)
>>> count = 0
>>> while True:
... i, j = get_one(matrix)
... if i and j: #found a one
... count += 1
... flood(i, j, matrix)
This is just the same like finding strongly connected components in a graph, but with the whole thing extended to 3 dimensions. So you can use any of the linear time algorithms for 2D graphs and adapt the DFS also for the 3rd dimension. This should be straight forward.
As those algorithms are linear time you can't get better in terms of running time complexity.

Reducing the Average Number of Comparisons in Selection

The problem here is to reduce the average number of comparisons need in a selection sort.
I am reading an article on this and here is text snippet:
More generally, a sample S' of s elements is chosen from the n
elements. Let "delta" be some number, which we will choose later so
as to minimize the average number of comparisons used by the
procedure. We find the (v1 = (k * s)/(n - delta))th and (v2 = (k* * s)/(n + delta)
)th smallest elements in S'. Almost certainly, the kth smallest
element in S will fall between v1 and v2, so we are left with a
selection problem on (2 * delta) elements. With low probability, the
kth smallest element does not fall in this range, and we have
considerable work to do. However, with a good choice of s and delta,
we can ensure, by the laws of probability, that the second case does
not adversely affect the total work.
I do not follow the above text. Can anyone please explain to me with examples. How did the author reduce to 2 * delta elements? And how does he know that there is a low probablity that element does not fall into this category.
Thanks!
The basis for the idea is that the normal selection algorithm has linear runtime complexity, but in practical terms is slow. We need to sort all the elements in groups of five, and recursively do even more work. O(n) but with too large a constant. The idea then, is to reduce the number of comparisons in the selection algorithm (not a selection sort necessarily). Intuitively it is the same as in basic statistics; if I take a sample subspace of large enough proportion, it is likely that the distribution of data in the subspace adequately reflects the data in the whole space.
So if I'm looking for the kth number in a set of size one million, I could instead take say 10 000 (already one hundredth the size), which is still large enough to be a good representation of the global distribution, and look for the k/100th number. That's simple scaling. So if the space was 10 and I was looking for the 3rd, that's like looking for the 30th in 100, or the 300th in 1000, etc. Essentially k/S = k'/S' (where we're looking for the kth number in S, and we translate that to the k'th number in S' our subspace) and therefore k' = k*S'/S which should look familiar, since in the text you quoted S' is denoted by s, and S by n, and that's the same fraction quoted.
Now in order to take statistical fluctuations into account, we don't assume that the subspace will be a perfect representation of the data's distribution, so we allow for some fluctuation, namely, delta. We say let's find the k'th-delta and k'th+delta elements in S', and then we can say with great certainty (i.e. high mathematical probability) that the kth value from S is in the interval (k'th-delta, k'th+delta).
To wrap it all up we perform these two selections on S', then partition S accordingly, and now do [normal] selection on the much smaller interval in the partition. This ends up being almost optimal for the elements outside the interval, because we don't do selection on those, only partition them. So the selection process is faster, because we have reduced the problem size from S to S'.

Resources