Problem Statement in English
You’re given a square of side length side and an array points where points[i] = [x, y] is the coordinate of the i-th point on the perimeter of the square. You are also given an integer k.
You have to find the maximum distance between any two points on the perimeter of the square such that there are at least k points on the perimeter of the square that are at least that distance apart.
Return the maximum distance.
Approach
To make calculating the distance easier, we unroll the square into a linear array. We can do this by iterating through the points and calculating their distance from the starting point (0, 0) in a clockwise manner.
So for points on the:
- Bottom edge: distance = x
- Right edge: distance = side + y
- Top edge: distance = 2 * side + (side - x)
- Left edge: distance = 3 * side + (side - y)
Now we need to find the maximum distance d such that there are at least k points that are at least d apart. But the question is what is our starting point?
Our starting point needs to be such that we’re able select atleast k - 1 points after it, and the distance between all each pair of points is atleast d. So this means the first point and the last point we select should be atleast d apart.
Since we need the points to be in order, we should sort the linear array.
Thus our starting point needs to be early as possible and will also be before points[0] + d.
To figure out the actual points we select, we can use binary search to find the next point that is atleast d apart from the last point we selected.
We can use binary search to find the maximum d that satisfies the above condition.
And we’re done!
Solution in Python
class Solution:
def maxDistance(self, side: int, points: List[List[int]], k: int) -> int:
linear = []
for x, y in points:
if y == 0: # Bottom
linear.append(x)
elif x == side: # Right
linear.append(side + y)
elif y == side: # Top
linear.append(2 * side + (side - x))
else: # Left
linear.append(3 * side + (side - y))
linear.sort()
n = len(linear)
perimeter = 4 * side
def check(dist):
for i in range(n):
if linear[i] > linear[0] + dist: break
count = 1
last_pos = linear[i]
start_pos = linear[i]
curr = i
for _ in range(k - 1):
target = last_pos + dist
idx = bisect_left(linear, target)
if idx < n:
last_pos = linear[idx]
count += 1
else:
break
if count == k and (perimeter - (last_pos - start_pos)) >= dist:
return True
return False
low, high = 0, side
ans = 0
while low <= high:
mid = (low + high) // 2
if mid == 0:
low = 1
continue
if check(mid):
ans = mid
low = mid + 1
else:
high = mid - 1
return ans
Complexity
Time: $O(n \log n)$
Since we sort the array and for each distance we check, we iterate through the points and do a binary search.Space: $O(n)$
Since we store the linear array.
Mistakes I Made
I had to look this up :(
And we are done.