On a campus represented as a 2D grid, there are n workers and m bikes, with n <= m. You are given a list of the workers' locations: workers[i] = (xi, yi) and a list of bike locations: bikes[j] = (xj, yj). All the workers and bikes are distinct.
Assign a bike to each worker such that the sum of the Manhattan distances between each worker and their assigned bike is minimized.
The Manhattan distance between two points (a, b) and (c, d) is |a - c| + |b - d|.
Return an array result of size n, where result[i] is the index of the bike assigned to the ith worker.
Example 1:
Input: workers = [[0,0],[2,1]], bikes = [[1,2],[3,3]]
Output: [1,0]
Explanation:
The bike at [1,2] is assigned to the worker at [0,0]; the bike at [3,3] is assigned to the worker at [2,1].
Example 2:
Input: workers = [[0,0],[1,1],[2,0]], bikes = [[1,0],[2,2],[2,1]]
Output: [0,2,1]
Constraints:
n == workers.lengthm == bikes.length1 <= n <= m <= 1000workers[i].length == bikes[j].length == 20 <= xi, yi < 1000When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
We want to assign bikes to workers so that the total distance between workers and their assigned bikes is as small as possible. The brute force approach considers every single possible assignment of bikes to workers, calculating the total distance for each.
Here's how the algorithm would work step-by-step:
import itertools
def campus_bikes_brute_force(
workers_positions, bikes_positions
):
number_of_workers = len(workers_positions)
number_of_bikes = len(bikes_positions)
# Ensure there are at least as many bikes as workers
if number_of_bikes < number_of_workers:
return -1
minimum_total_distance = float('inf')
# Generate all possible bike assignments to workers.
for bike_assignment in itertools.permutations(
range(number_of_bikes), number_of_workers
):
current_total_distance = 0
# Calculate the total distance for the current assignment.
for worker_index in range(number_of_workers):
bike_index = bike_assignment[worker_index]
worker_x, worker_y = workers_positions[worker_index]
bike_x, bike_y = bikes_positions[bike_index]
current_distance = abs(worker_x - bike_x) + abs(
worker_y - bike_y
)
current_total_distance += current_distance
# Update minimum total distance if necessary.
minimum_total_distance = min(
minimum_total_distance, current_total_distance
)
return minimum_total_distanceThe best way to assign bikes to workers is to consider the distances between each worker and each bike. We want to prioritize assigning bikes that are closer to workers and avoid assigning the same bike or worker multiple times. It is more efficient than trying all combinations.
Here's how the algorithm would work step-by-step:
def assign_bikes(workers, bikes):
distances = []
number_of_workers = len(workers)
number_of_bikes = len(bikes)
for worker_index in range(number_of_workers):
for bike_index in range(number_of_bikes):
worker_x, worker_y = workers[worker_index]
bike_x, bike_y = bikes[bike_index]
distance = abs(worker_x - bike_x) + abs(worker_y - bike_y)
distances.append((distance, worker_index, bike_index))
distances.sort()
assigned_bikes = [None] * number_of_workers
worker_assigned = [False] * number_of_workers
bike_assigned = [False] * number_of_bikes
bikes_assigned_count = 0
for distance, worker_index, bike_index in distances:
# Only proceed if both worker and bike are unassigned
if not worker_assigned[worker_index] and not bike_assigned[bike_index]:
assigned_bikes[worker_index] = bike_index
worker_assigned[worker_index] = True
bike_assigned[bike_index] = True
bikes_assigned_count += 1
# Exit once all workers are assigned
if bikes_assigned_count == number_of_workers:
break
return assigned_bikes| Case | How to Handle |
|---|---|
| Empty worker or bike array | Return an empty list or an error, as no assignments can be made without workers or bikes. |
| Workers and bikes have identical positions. | The distance calculation will result in zero, which should be handled correctly by the sorting or priority queue mechanism. |
| Maximum number of workers and bikes close to constraint limits (e.g., 1000 workers and 1000 bikes). | Ensure the solution scales efficiently, especially the distance calculation and assignment steps, avoiding excessive computation. |
| Integer overflow in distance calculation due to large coordinate values. | Use appropriate data types (e.g., long) to prevent integer overflow when calculating Manhattan distance. |
| Cases where the workers and bikes are far apart and results in very large distances. | The solution should still perform correctly, handling potentially large integer values appropriately and preventing performance degradation due to unnecessary calculations. |
| Number of workers and bikes are significantly different (e.g., many more workers than bikes or vice versa). | The algorithm should efficiently handle such unbalanced scenarios, prioritizing the closest assignments and ensuring all workers/bikes are considered if possible. |
| Coordinates are negative. | Manhattan distance calculation will handle negative coordinates correctly. |
| Duplicate worker or bike locations. | The assignment logic should not get stuck trying to reassign the same location and should correctly assign the closest available bike to each worker. |