Given two arrays, players
and runners
, both representing positions along a line, and an integer k
representing the maximum distance a player can catch a runner, determine the maximum number of runners that can be caught by the players. Each player can catch at most one runner, and each runner can be caught by at most one player. A player can only catch a runner if their positions differ by at most k
(i.e., abs(players[i] - runners[j]) <= k
).
The goal is to find the maximum number of runners that can be caught under these constraints.
At first glance, the problem seems to invite a brute-force approach: for every player, check all runners to see if they are within distance k
and have not been caught yet. However, this leads to a highly inefficient solution with a time complexity of O(N*M), where N and M are the lengths of the players
and runners
arrays.
Instead, we can draw an analogy to the "maximum bipartite matching" or "interval matching" problems, where each player is trying to be paired with a runner within a certain range. Since both arrays represent positions, sorting them allows us to efficiently pair players and runners using a two-pointer technique.
The key insight is that by sorting both arrays, we can always try to match the leftmost (smallest position) player with the leftmost available runner within their reach, ensuring no one is skipped unnecessarily.
To solve the problem efficiently, follow these steps:
players
and runners
arrays in ascending order. This allows us to efficiently find the nearest available runner for each player.
players
(i
) and one for runners
(j
).
abs(players[i] - runners[j]) <= k
, we have a match. Increment both i
and j
, and increment the count of caught runners.
players[i] < runners[j]
, move the player pointer forward (i++
), since the current player is too far left to catch the runner.
j++
), since the runner is too far left to be caught by the current player.
This approach ensures we never revisit a player or runner, making the solution efficient and optimal.
Suppose players = [1, 4, 5]
, runners = [2, 3, 6]
, and k = 1
.
players = [1, 4, 5]
, runners = [2, 3, 6]
.
i = 0
, j = 0
: abs(1 - 2) = 1 ≤ 1
, match! Increment both pointers and matches = 1.
i = 1
, j = 1
: abs(4 - 3) = 1 ≤ 1
, match! Increment both pointers and matches = 2.
i = 2
, j = 2
: abs(5 - 6) = 1 ≤ 1
, match! Increment both pointers and matches = 3.
If, for example, k = 0
, then no player could catch any runner unless they are at the exact same position.
Brute-force approach:
players
and runners
.The optimized approach is much faster and suitable for large inputs.
By sorting both arrays and using a two-pointer technique, we efficiently pair up players and runners within the allowed distance, ensuring each is used at most once. This solution is elegant, optimal, and leverages classic algorithmic techniques for matching problems, making it both practical and easy to understand.
def max_caught(players, runners, k):
players.sort()
runners.sort()
i = j = count = 0
while i < len(players) and j < len(runners):
if abs(players[i] - runners[j]) <= k:
count += 1
i += 1
j += 1
elif players[i] < runners[j]:
i += 1
else:
j += 1
return count
#include <vector>
#include <algorithm>
#include <cstdlib>
using namespace std;
int maxCaught(vector<int>& players, vector<int>& runners, int k) {
sort(players.begin(), players.end());
sort(runners.begin(), runners.end());
int i = 0, j = 0, count = 0;
while (i < players.size() && j < runners.size()) {
if (abs(players[i] - runners[j]) <= k) {
count++;
i++;
j++;
} else if (players[i] < runners[j]) {
i++;
} else {
j++;
}
}
return count;
}
import java.util.*;
public class Solution {
public int maxCaught(int[] players, int[] runners, int k) {
Arrays.sort(players);
Arrays.sort(runners);
int i = 0, j = 0, count = 0;
while (i < players.length && j < runners.length) {
if (Math.abs(players[i] - runners[j]) <= k) {
count++;
i++;
j++;
} else if (players[i] < runners[j]) {
i++;
} else {
j++;
}
}
return count;
}
}
function maxCaught(players, runners, k) {
players.sort((a, b) => a - b);
runners.sort((a, b) => a - b);
let i = 0, j = 0, count = 0;
while (i < players.length && j < runners.length) {
if (Math.abs(players[i] - runners[j]) <= k) {
count++;
i++;
j++;
} else if (players[i] < runners[j]) {
i++;
} else {
j++;
}
}
return count;
}