You are given an array points
representing integer coordinates of some points on a 2D plane, where points[i] = [x_i, y_i]
. The distance between two points is defined as their Manhattan distance. Return the minimum possible value for the maximum distance between any two points by removing exactly one point.
For example:
points = [[3,10],[5,15],[10,2],[4,4]]
The maximum distance after removing each point is the following:
|5 - 10| + |15 - 2| = 18
.|3 - 10| + |10 - 2| = 15
.|5 - 4| + |15 - 4| = 12
.|5 - 10| + |15 - 2| = 18
.12 is the minimum possible maximum distance between any two points after removing exactly one point.
Can you come up with an algorithm with optimal time and space complexity?
The most straightforward approach is to iterate through each point, remove it temporarily, calculate the maximum Manhattan distance between all remaining pairs, and then keep track of the minimum of these maximum distances. This is a brute-force solution.
def manhattan_distance(p1, p2):
return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
def solve_naive(points):
n = len(points)
min_max_distance = float('inf')
for i in range(n):
temp_points = points[:i] + points[i+1:]
max_distance = 0
for j in range(len(temp_points)):
for k in range(j + 1, len(temp_points)):
max_distance = max(max_distance, manhattan_distance(temp_points[j], temp_points[k]))
min_max_distance = min(min_max_distance, max_distance)
return min_max_distance
temp_points
holds almost all the original points.To improve the time complexity, we need to avoid recalculating the maximum distance between all pairs after removing each point. Instead, we can precompute all pairwise Manhattan distances and then efficiently determine the maximum distance after removing a point.
def solve_optimal(points):
n = len(points)
distances = {}
# Precompute distances
for i in range(n):
for j in range(i + 1, n):
dist = manhattan_distance(points[i], points[j])
distances[(i, j)] = dist
min_max_distance = float('inf')
for i in range(n):
max_distance = 0
for j in range(n):
if i == j: # Skip the removed point
continue
for k in range(j + 1, n):
if i == k:
continue
if (j, k) in distances:
max_distance = max(max_distance, distances[(j, k)])
elif (k, j) in distances:
max_distance = max(max_distance, distances[(k, j)])
else:
max_distance = max(max_distance, manhattan_distance(points[j], points[k]))
min_max_distance = min(min_max_distance, max_distance)
return min_max_distance
distances
dictionary stores the Manhattan distances between all pairs of points.Instead of calculating all pairs after removing a node, we could find the initial max distance, and see if the removed node was part of that max distance. If not, return it. Otherwise, loop through other distances.
def solve_even_more_optimal(points):
n = len(points)
min_max_distance = float('inf')
for i in range(n):
temp_points = points[:i] + points[i+1:]
#Find max distance
max_distance = 0
for j in range(len(temp_points)):
for k in range(j + 1, len(temp_points)):
max_distance = max(max_distance, manhattan_distance(temp_points[j], temp_points[k]))
min_max_distance = min(min_max_distance, max_distance)
return min_max_distance
temp_points
holds almost all the original points.The brute-force solution precomputes the Manhattan distances between all pairs of points, then iterates through possible removal points, recalculating pairwise distances. While this improves upon the extremely naive solution, its time complexity remains O(N^3). Space complexity is O(N^2) due to storing pairwise distances.