A delivery company wants to build a new service center in a new city. The company knows the positions of all the customers in this city on a 2D-Map and wants to build the new center in a position such that the sum of the euclidean distances to all customers is minimum.
Given an array positions where positions[i] = [xi, yi] is the position of the ith customer on the map, return the minimum sum of the euclidean distances to all customers.
In other words, you need to choose the position of the service center [xcentre, ycentre] such that the following formula is minimized:
Answers within 10-5 of the actual value will be accepted.
Explanation: As shown, you can see that choosing [xcentre, ycentre] = [1, 1] will make the distance to each customer = 1, the sum of all distances is 4 which is the minimum possible we can achieve.
Example 2:
1
2
3
4
Input:
positions = [[1,1],[3,3]]
Output:
2.82843
Explanation: The minimum possible sum of distances = sqrt(2) + sqrt(2) = 2.82843
Variation of Problem - Best Position for Reddit Offline Kiosk Problem#
Reddit is so successful online, that it has decided to open an offline kiosk for people to get their physical front page of the internet - now we just need to decide where to build it. Fortunately we have already located the perfect city to put our first test kiosk, and like all cities, it happens to be a perfect grid. We also happen to know the locations of all of our happy customers as intersections on the grid. Given this customer data, what is the best place to put our kiosk?
Here is an ascii grid demonstrating this problem. Streets are lines, and locations of customers are smiley faces. The asterisk is an example place for a kiosk on the grid.
The math solution for this problem is to find the geometric median, which can be done using the Weiszfeld’s algorithm. But we can use approximation solutiont to solve this and Leetcode will accept it. I believe that Leetcode did this on purpose so non-math solutions are accepted during the contest.
The optimal position to minimize the sum of Euclidean distances to all points is the geometric median. There is no closed-form solution for the geometric median in 2D, but we can approximate it efficiently.
The idea is to start with a large search area and iteratively “zoom in” on the region with the smallest total distance, reducing the search step each time. This is similar to a multi-resolution grid search or hill climbing, and works well for this problem’s constraints.
Start with a large search area with lower precision (e.g., the whole grid, center at (50, 50)).
Iteratively search a grid of candidate points around the current center, with a given step size (delta).
Update the center to the point with the smallest total distance.
Reduce the step size (zoom in) and repeat until the step is very small (e.g., < 1e-5). Once get the closest point, we search around this point with higher precision.
This process efficiently narrows down to a point that is very close to the true geometric median.
⏰ Time complexity:O((delta_0/epsilon)^2 * n), where delta_0 is the initial search range (e.g., 100), epsilon is the final precision (e.g., 1e-5), and n is the number of positions. For each zoom level, we check a grid of points, and the number of levels is O(log(delta_0/epsilon)).
🧺 Space complexity:O(1) (ignoring input), as only a few variables are used for the search.
Method 2 – Hill Climbing (Modified Binary Search)#
This method uses a hill climbing or greedy local search approach. We start from an initial guess (the centroid/average of all points), and iteratively move in the direction (north, south, east, west) that most reduces the total distance. If no direction improves the result, we reduce the step size and repeat, until the step is very small.
This is a fast and practical way to approximate the geometric median, and converges quickly for small input sizes.
import math
classSolution:
defgetMinDistSum(self, positions: list[list[int]]) -> float:
min_step =1e-6 dirs = [(-1,0),(1,0),(0,-1),(0,1)]
n = len(positions)
cx = sum(p[0] for p in positions) / n
cy = sum(p[1] for p in positions) / n
deftotal_dist(x, y):
return sum(math.hypot(p[0] - x, p[1] - y) for p in positions)
step =50.0 ans = total_dist(cx, cy)
while step > min_step:
moved =Falsefor dx, dy in dirs:
nx, ny = cx + dx * step, cy + dy * step
nd = total_dist(nx, ny)
if nd < ans:
ans = nd; cx = nx; cy = ny; moved =Trueifnot moved:
step /=2return ans
⏰ Time complexity:O(n * log(R/epsilon)), where n is the number of positions, R is the initial search range (e.g., 100), and epsilon is the final precision. Each step checks 4 directions, and the number of steps is O(log(R/epsilon)).
🧺 Space complexity:O(1) (ignoring input), as only a few variables are used for the search.