The "Campus Bikes" problem asks you to assign bikes to workers on a campus grid. Each worker and bike has a location represented by a pair of coordinates. The goal is to assign each worker exactly one bike, such that:
The function receives two lists: workers
and bikes
, both containing coordinate pairs. The output should be a list result
where result[i]
is the index of the bike assigned to the i
th worker.
At first glance, the problem resembles an assignment or matching problem. The most straightforward approach is to compute the distance from each worker to every bike and, for each worker, always pick the nearest available bike. However, since bike assignments are exclusive, we need to ensure that no two workers are assigned the same bike.
A brute-force solution would try every possible assignment, but this quickly becomes infeasible as the number of workers and bikes grows. Therefore, we need a more efficient way to ensure that workers are assigned their closest available bikes, while handling tie-breakers as specified.
The key insight is to process all possible worker-bike pairs, sorted by distance (and then by worker and bike index), and for each pair, assign the bike to the worker if both are still unassigned. This greedy approach ensures that assignments are made in the required priority order.
The optimized solution leverages sorting and greedy assignment. Here’s a step-by-step breakdown:
This approach is efficient because sorting all pairs is manageable for the given constraints, and assignment is done in a single pass.
Suppose we have the following input:
workers = [[0,0],[2,1]]
bikes = [[1,2],[3,3]]
Step 1: Compute all distances
Step 2: Sort pairs
Sorted list: [(2,1,0), (3,0,0), (3,1,1), (6,0,1)]
Step 3: Assign bikes
Result: Worker 0 gets Bike 1, Worker 1 gets Bike 0. Output: [1, 0]
Brute-force approach:
Trying all possible assignments is O((N!) * N), where N is the number of workers/bikes. This is not feasible for large N.
Optimized approach:
Overall, the time complexity is O(N*M*log(N*M)), and space complexity is O(N*M) for storing all pairs.
The "Campus Bikes" problem is elegantly solved by precomputing all possible worker-bike distances and sorting them according to the rules. By greedily assigning the closest available bikes, we ensure correctness and efficiency. The use of sorting and simple assignment tracking makes the solution both intuitive and powerful, avoiding the pitfalls of brute-force approaches.
class Solution:
def assignBikes(self, workers, bikes):
pairs = []
for i, (wx, wy) in enumerate(workers):
for j, (bx, by) in enumerate(bikes):
dist = abs(wx - bx) + abs(wy - by)
pairs.append((dist, i, j))
pairs.sort()
res = [-1] * len(workers)
assigned_bikes = set()
assigned_workers = set()
count = 0
for dist, i, j in pairs:
if i not in assigned_workers and j not in assigned_bikes:
res[i] = j
assigned_workers.add(i)
assigned_bikes.add(j)
count += 1
if count == len(workers):
break
return res
class Solution {
public:
vector<int> assignBikes(vector<vector<int>>& workers, vector<vector<int>>& bikes) {
vector<tuple<int, int, int>> pairs;
int n = workers.size(), m = bikes.size();
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
int dist = abs(workers[i][0] - bikes[j][0]) + abs(workers[i][1] - bikes[j][1]);
pairs.push_back({dist, i, j});
}
}
sort(pairs.begin(), pairs.end());
vector<int> res(n, -1);
vector<bool> worker_assigned(n, false), bike_assigned(m, false);
int count = 0;
for (auto& p : pairs) {
int dist, i, j;
tie(dist, i, j) = p;
if (!worker_assigned[i] && !bike_assigned[j]) {
res[i] = j;
worker_assigned[i] = true;
bike_assigned[j] = true;
count++;
if (count == n) break;
}
}
return res;
}
};
class Solution {
public int[] assignBikes(int[][] workers, int[][] bikes) {
List<int[]> pairs = new ArrayList<>();
int n = workers.length, m = bikes.length;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
int dist = Math.abs(workers[i][0] - bikes[j][0]) + Math.abs(workers[i][1] - bikes[j][1]);
pairs.add(new int[]{dist, i, j});
}
}
pairs.sort((a, b) -> {
if (a[0] != b[0]) return a[0] - b[0];
if (a[1] != b[1]) return a[1] - b[1];
return a[2] - b[2];
});
int[] res = new int[n];
Arrays.fill(res, -1);
boolean[] workerAssigned = new boolean[n];
boolean[] bikeAssigned = new boolean[m];
int count = 0;
for (int[] p : pairs) {
int dist = p[0], i = p[1], j = p[2];
if (!workerAssigned[i] && !bikeAssigned[j]) {
res[i] = j;
workerAssigned[i] = true;
bikeAssigned[j] = true;
count++;
if (count == n) break;
}
}
return res;
}
}
var assignBikes = function(workers, bikes) {
let pairs = [];
for (let i = 0; i < workers.length; i++) {
for (let j = 0; j < bikes.length; j++) {
let dist = Math.abs(workers[i][0] - bikes[j][0]) + Math.abs(workers[i][1] - bikes[j][1]);
pairs.push([dist, i, j]);
}
}
pairs.sort((a, b) => {
if (a[0] !== b[0]) return a[0] - b[0];
if (a[1] !== b[1]) return a[1] - b[1];
return a[2] - b[2];
});
let res = new Array(workers.length).fill(-1);
let assignedBikes = new Set();
let assignedWorkers = new Set();
let count = 0;
for (let [dist, i, j] of pairs) {
if (!assignedWorkers.has(i) && !assignedBikes.has(j)) {
res[i] = j;
assignedWorkers.add(i);
assignedBikes.add(j);
count++;
if (count === workers.length) break;
}
}
return res;
};