Reputation: 441
I have a n x n
grid. All the grids have numbers in them. I need to find 4 points in a grid such that they make a rectangle and the smallest element among them is as big as it can be. The minimum is taken from the ends of the rectange, meaning the corner elements.
Example
1 1 1
2 1 2
3 1 4
The answer is obiously (2,1)
,(2,3)
,(3,1
) and (3,3)
, because then the set is 2,2,3,4
and min of it is 2
, and obviously we can't do better.
The only possible solution I can think of is somethow brute-forcy. For each element (n^2
of them), we check every element that could be opposite of it in a rectangle. In the example below when we check the red element, the possible element are the yellow ones.
Such solutions is obviously O(n^4)
, which is not desirable.
Anyone know a better way?
Upvotes: 2
Views: 252
Reputation: 24677
for row1 = 1 .. n:
for row2 = row1 + 1 .. n:
h = empty min heap
for column = 1 .. n:
x = min(grid[row1, column], grid[row2, column])
push x to h
if h.size > 2:
pop h
best = max(best, h.min)
Unlike previous approach, this one needs O(n2) temporary space.
This algorithm is based on binary search, which works better when dealing with integer numbers in limited range. So simple preprocessing is needed to compress range of values in the grid. Sort grid cells by their value and substitute these values by indexes in sorted array. Alternatively (if there are duplicates among original values) we could assign consecutive natural numbers to each unique number in the grid (in sorted order), in this case time complexity decreases to O(n2 log U), where U
is the number of unique numbers.
range = [1 .. U] (where U is maximal cell value)
binary search, stop when range is empty:
m = range.middle
A = empty 2D array of size n*n
for row = 1 .. n:
L = empty linked list
for each column:
if grid[row, column] >= m:
append column to L
for column1 = L.begin .. L.end:
for column2 = column1.next .. L.end:
if A[column1, column2] is empty:
A[column1, column2] = row
else:
result = (A[column1, column2], row, column1, column2)
range = [m .. range.max]
continue binary search (found)
range = [range.min .. m]
continue binary search (not found)
Upvotes: 1