You have k
servers numbered from 0
to k-1
that are being used to handle multiple requests simultaneously. Each server has infinite computational capacity but cannot handle more than one request at a time. The requests are assigned to servers according to a specific algorithm:
ith
(0-indexed) request arrives.(i % k)th
server is available, assign the request to that server.ith
server is busy, try to assign the request to the (i+1)th
server, then the (i+2)th
server, and so on.You are given a strictly increasing array arrival
of positive integers, where arrival[i]
represents the arrival time of the ith
request, and another array load
, where load[i]
represents the load of the ith
request (the time it takes to complete). Your goal is to find the busiest server(s). A server is considered busiest if it handled the most number of requests successfully among all the servers.
Return a list containing the IDs (0-indexed) of the busiest server(s). You may return the IDs in any order.
Example 1:
Input: k = 3, arrival = [1,2,3,4,5], load = [5,2,3,3,3] Output: [1] Explanation: All of the servers start out available. The first 3 requests are handled by the first 3 servers in order. Request 3 comes in. Server 0 is busy, so it's assigned to the next available server, which is 1. Request 4 comes in. It cannot be handled since all servers are busy, so it is dropped. Servers 0 and 2 handled one request each, while server 1 handled two requests. Hence server 1 is the busiest server.
Example 2:
Input: k = 3, arrival = [1,2,3,4], load = [1,2,1,2] Output: [0] Explanation: The first 3 requests are handled by first 3 servers. Request 3 comes in. It is handled by server 0 since the server is available. Server 0 handled two requests, while servers 1 and 2 handled one request each. Hence server 0 is the busiest server.
Example 3:
Input: k = 3, arrival = [1,2,3], load = [10,12,11] Output: [0,1,2] Explanation: Each server handles a single request, so they are all considered the busiest.
Constraints:
1 <= k <= 105
1 <= arrival.length, load.length <= 105
arrival.length == load.length
1 <= arrival[i], load[i] <= 109
arrival
is strictly increasing.This problem involves assigning incoming requests to servers, considering server availability and request load. The goal is to identify the servers that handled the most requests. The solution uses a combination of data structures to efficiently manage server availability and request processing.
Approach:
Data Structures:
free
: A sorted set (or equivalent) to store the IDs of available servers. A sorted set provides efficient insertion, deletion, and searching for the next available server.busy
: A min-heap (priority queue) to store the currently busy servers. Each element in the heap contains the server's ID and its release time. The min-heap ensures we can quickly identify the next available server.cnt
: An array to count the number of requests handled by each server.Request Processing:
busy
heap that have finished processing their requests (release time <= current arrival time). Add these servers back to the free
set.i % k
, but if that server is busy, we use the sorted set free
to find the next available server in a wrapped-around manner (starting from i % k
).free
will be empty).busy
heap with its release time, remove the server from free
, and increment its request count in cnt
.Find Busiest Servers: After processing all requests, find the maximum number of requests handled among all servers (mx
). Then, return the list of server IDs that have handled mx
requests.
Time Complexity:
The time complexity is dominated by the iteration through the requests. Each operation on the free
sorted set and the busy
min-heap (insertion, deletion, searching) takes O(log k) time, where k is the number of servers. Therefore, the overall time complexity is O(N log k), where N is the number of requests.
Space Complexity:
The space complexity is O(k) to store free
, busy
, and cnt
. This is because the number of servers is fixed and independent of the number of requests.
Code Explanation (Python):
The Python code utilizes the SortedList
from the sortedcontainers
library (a more efficient sorted set implementation than Python's built-in set
). The code follows the algorithm described above:
from sortedcontainers import SortedList
import heapq
class Solution:
def busiestServers(self, k: int, arrival: List[int], load: List[int]) -> List[int]:
free = SortedList(range(k))
busy = [] # Use a list as a min-heap
cnt = [0] * k
for i, (start, t) in enumerate(zip(arrival, load)):
while busy and busy[0][0] <= start:
free.add(busy[0][1])
heapq.heappop(busy) # Correct heappop usage
if not free:
continue
j = free.bisect_left(i % k)
if j == len(free):
j = 0
server = free[j]
cnt[server] += 1
heapq.heappush(busy, (start + t, server)) # Correct heappush usage
free.remove(server)
mx = max(cnt)
return [i for i, v in enumerate(cnt) if v == mx]
The other languages (Java, C++, Go) implement similar logic, using their respective priority queue and sorted set implementations. Note that Go's solution uses a custom heap
and redblacktree
for efficient priority queue and sorted set functionality. Java uses the standard PriorityQueue
and TreeSet
. C++ leverages priority_queue
and set
.