The "Magnetic Force Between Two Balls" problem asks you to arrange m
balls in n
baskets positioned along a line, such that the minimum magnetic force (the distance between any two balls) is as large as possible.
You are given an array position
of length n
, where position[i]
is the location of the i
-th basket. You need to choose m
baskets to place the balls, with exactly one ball per chosen basket.
The magnetic force between any two balls is the absolute difference between their basket positions. Your goal is to maximize the minimum magnetic force between any two balls.
Constraints:
At first glance, one might think about checking all possible ways to place m
balls in n
baskets and then calculating the minimum distance for each configuration. However, this approach would be computationally infeasible due to the enormous number of combinations, especially with large input sizes.
Instead, we can reframe the problem: for a given minimum distance d
, can we place all m
balls such that every pair is at least d
apart? If we can check this efficiently, we can use binary search to find the largest possible d
.
This shift from "searching for a configuration" to "searching for the maximum feasible minimum distance" is the key insight. It allows us to use binary search on the answer, which is a common technique for optimization problems with a monotonic property.
We use a binary search approach to maximize the minimum magnetic force:
mid
, check if it's possible to place all m
balls such that the distance between any two is at least mid
.
mid
away from the last placed ball. Count how many balls you can place.
m
balls, try a larger force (move the binary search right); otherwise, try a smaller force (move left).
This approach is efficient because the greedy check is linear in the number of baskets, and binary search reduces the number of candidate forces to logarithmic scale.
Example:
position = [1, 2, 8, 4, 9]
, m = 3
[1, 2, 4, 8, 9]
left = 1
, right = 8
(9 - 1)
3
.
Thus, the largest minimum magnetic force possible is 3.
m
baskets from n
(which is O(n^m)
), and for each, compute the minimum distance. This is not feasible for large n
.
O(n \log n)
O(\log D)
iterations, where D
is the max possible distance (up to 109)O(n)
O(n \log n + n \log D)
O(1)
extra (if sorting in place), or O(n)
if making a copy.
The "Magnetic Force Between Two Balls" problem is cleverly solved by reframing it as a search for the largest feasible minimum distance, rather than brute-forcing all arrangements. By combining binary search with a greedy placement check, we achieve an elegant and efficient solution that scales to large inputs. The key insight is recognizing the monotonic relationship between the minimum force and the possibility of placing all balls, allowing binary search to quickly zero in on the optimal answer.
class Solution:
def maxDistance(self, position: List[int], m: int) -> int:
position.sort()
left, right = 1, position[-1] - position[0]
answer = 0
def can_place(force):
count = 1
last = position[0]
for pos in position[1:]:
if pos - last >= force:
count += 1
last = pos
if count == m:
return True
return False
while left <= right:
mid = (left + right) // 2
if can_place(mid):
answer = mid
left = mid + 1
else:
right = mid - 1
return answer
class Solution {
public:
int maxDistance(vector<int>& position, int m) {
sort(position.begin(), position.end());
int left = 1, right = position.back() - position.front(), answer = 0;
auto can_place = [&](int force) {
int count = 1, last = position[0];
for (int i = 1; i < position.size(); ++i) {
if (position[i] - last >= force) {
count++;
last = position[i];
if (count == m) return true;
}
}
return false;
};
while (left <= right) {
int mid = left + (right - left) / 2;
if (can_place(mid)) {
answer = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return answer;
}
};
class Solution {
public int maxDistance(int[] position, int m) {
Arrays.sort(position);
int left = 1, right = position[position.length - 1] - position[0];
int answer = 0;
while (left <= right) {
int mid = left + (right - left) / 2;
if (canPlace(position, m, mid)) {
answer = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return answer;
}
private boolean canPlace(int[] position, int m, int force) {
int count = 1, last = position[0];
for (int i = 1; i < position.length; i++) {
if (position[i] - last >= force) {
count++;
last = position[i];
if (count == m) return true;
}
}
return false;
}
}
var maxDistance = function(position, m) {
position.sort((a, b) => a - b);
let left = 1, right = position[position.length - 1] - position[0];
let answer = 0;
function canPlace(force) {
let count = 1, last = position[0];
for (let i = 1; i < position.length; i++) {
if (position[i] - last >= force) {
count++;
last = position[i];
if (count === m) return true;
}
}
return false;
}
while (left <= right) {
let mid = Math.floor((left + right) / 2);
if (canPlace(mid)) {
answer = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return answer;
};