Yesterday I read a problem which can be translated into the following problem with slight modification:
The coordinate of a dot is expressed by (x, y) in a 2D space.
I have come out with a solution in O(logN) if the dots are sorted on x coordinate.
It uses a divide-and-conquer approach. I divide the dots array based on their x coordinate in the 2D space.
Consider the 2D case.
Assume each dot is expressed in the following data structure:
class Point {
public float getX();
public float getY();
}
We have two inputs: dot array ARRAY
, and another dot D
.
Initially, we would like to partition ARRAY
into two parts: those dots that are on the "left" of D
, and those dots are on the "right" of D
.
int pivotIndex = partition(array, 0, array.length() - 1, d);
After partition, the dots with index less than pivotIndex
have x coordinate less than d.getX()
; the dots with index equal or greater than pivotIndex
have x coordinate equal or greater than d.getX()
.
If all dots are on the left side of D
, pivotIndex
would be array.length() - 1
. If all dots are on the right side of D
, pivotIndex
would be -1
. If some dots are on the left of D
and some dots are on the right of D
, then pivotIndex
would be between 0
and array.length() - 1
. For dots having the same x coordinate as D
, they are considered as on the "right" side.
Now, the next step is to search the nearest dot on each partition:
Point p1 = getNearestDot(array, 0, pivotIndex, d);
Point p2 = getNearestDot(array, pivotIndex + 1, array.length() - 1, d);
if (p1 == null) return p2;
if (p2 == null) return p1;
return nearer(p1, p2, d);
It is possible that all the dots in the ARRAY
are on the left side of D
, then p2 would be null in this case. Similarly, if all dots in the ARRAY
are on the right side of D
, then p1 would be null.
The algorithm of getNearestDot
works as below:
// Find the nearest dot in array[low...high] inclusive which is closest to point d
Point getNearestDot(Point[] array, int low, int high, Point d) {
if (low > high)
return null;
if (low == high)
return array[low];
int middle = low + (high - low) >> 1;
Point p1 = getNearestDot(array, low, middle, d);
Point p2 = getNearestDot(array, middle + 1, high, d);
if (p1 == null) return p2;
if (p2 == null) return p1;
return nearer(p1, p2, d);
}
And finally, the function nearer(p1, p2, d) is to return either p1 or p2, whose distance to d is shorter.