Problem
You have n baskets arranged along a line at positions given in an array. Place exactly m balls into m distinct baskets so that the minimum magnetic force between any two balls (which equals the distance between their baskets) is as large as possible.
- Input:
position = [1, 2, 3, 4, 7],m = 3 - Output:
3 - Explanation: Place balls at positions 1, 4, and 7 โ the gaps are 3, 3, and 6, so the minimum force is 3.
A counter-example to show why greedy placement without binary search doesn't work: placing balls at 1, 2, 7 gives a minimum force of only 1, which is far from optimal.
Intuition
The answer is monotonic: if we can guarantee a minimum distance of d between all balls, then any smaller minimum distance is also achievable. This monotonicity means we can binary search on the answer itself. For any candidate minimum distance d, we sort the baskets and greedily place each ball at the earliest basket that is at least d away from the previous ball โ if this greedy scan places all m balls, then d is feasible.
Solution โ Binary Search on Answer
Sort the basket positions, then binary search over the candidate minimum distance. For each midpoint distance, run a greedy left-to-right scan to count how many balls can be placed with at least that spacing. Maximize the largest feasible distance.
- Sort
positionso baskets are in order. - Set binary search bounds:
left = 1,right = position[-1] - position[0]. - At each midpoint
mid, runcan_place(mid): start atposition[0], scan right, and place a ball whenever the gap from the last placed ball is โฅmid. - If
can_place(mid)returns true, recordmidas a valid answer and search the upper half for a larger feasible distance. - If false, search the lower half.
- Return the largest feasible distance found.
1def maxDistance(position: list[int], m: int) -> int:
2 position.sort()
3
4 def can_place(min_force: int) -> bool:
5 balls_placed = 1
6 last_position = position[0] # always place first ball at the leftmost basket
7
8 for i in range(1, len(position)):
9 if position[i] - last_position >= min_force: # gap is large enough
10 balls_placed += 1
11 last_position = position[i]
12 if balls_placed == m: # early exit once all balls are placed
13 return True
14
15 return balls_placed >= m
16
17 left, right = 1, position[-1] - position[0]
18 result = 0
19
20 while left <= right:
21 mid = (left + right) // 2
22 if can_place(mid):
23 result = mid # mid is feasible; try to do better
24 left = mid + 1
25 else:
26 right = mid - 1 # mid is too large; reduce the target distance
27
28 return resultTime: O(n log n + n log W) where W = max position โ min position (up to 10โน) โ sorting takes O(n log n) and the binary search runs O(log W) greedy scans each costing O(n).
Space: O(log n) โ only the call stack used by sorting; no auxiliary data structures.
Complexity Summary
| Approach | Time | Space | When to use |
|---|---|---|---|
| Binary Search on Answer | O(n log n + n log W) | O(log n) | Whenever you're maximizing a minimum (or minimizing a maximum) and a greedy feasibility check is easy to write |
Common Mistakes
- Forgetting to sort positions โ the greedy scan assumes positions are in ascending order; without sorting, you'll get wrong ball counts even for simple inputs.
- Using
>instead of>=in the gap check โ the problem asks for minimum force of at leastd, soposition[i] - lastPosition >= minForceis correct;>would reject valid placements. - Wrong upper bound for binary search โ searching up to
position[-1]instead ofposition[-1] - position[0]wastes iterations but doesn't break correctness; knowing the tight bound prevents confusion. - Not saving
resultseparately โ if you try to derive the answer asleft - 1after the loop, you need to verify the loop exits withleftone past the last feasible value; trackingresultexplicitly is safer and clearer. - Skipping the early exit inside
can_placeโ onceballs_placed == m, returning immediately avoids unnecessary scanning; omitting it is a performance issue, not a correctness bug, but it's a detail interviewers notice.
Related Problems
capacity-to-ship-packages-within-d-daysโ same binary-search-on-answer template, minimizing maximum load instead of maximizing minimum distancekoko-eating-bananasโ binary search on the eating speed, greedy feasibility check per candidatesplit-array-largest-sumโ minimize the maximum subarray sum using the same feasibility-check patternfind-minimum-in-rotated-sorted-arrayโ pure binary search on a sorted structure; builds the same left/right convergence intuitionsingle-element-in-a-sorted-arrayโ binary search on parity of indices, reinforcing that binary search applies beyond simple sorted lookups