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:
i<sup>th</sup>
(0-indexed) request arrives.(i % k)<sup>th</sup>
server is available, assign the request to that server.i<sup>th</sup>
server is busy, try to assign the request to the (i+1)<sup>th</sup>
server, then the (i+2)<sup>th</sup>
server, and so on.You are given a strictly increasing array arrival
of positive integers, where arrival[i]
represents the arrival time of the i<sup>th</sup>
request, and another array load
, where load[i]
represents the load of the i<sup>th</sup>
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.
For example:
k = 3, arrival = [1,2,3,4,5], load = [5,2,3,3,3]
In this case the output would be [1]
because server 1 handles two requests, which is more than any other server.
As another example:
k = 3, arrival = [1,2,3,4], load = [1,2,1,2]
In this case the output would be [0]
because server 0 handles two requests, which is more than any other server.
Can you describe an algorithm to solve this problem efficiently?
A brute force solution would involve iterating through each request and simulating the server assignment process as described in the problem statement. For each request, we'd check the availability of servers starting from (i % k)
and wrapping around until an available server is found. If all servers are busy, the request is dropped. We'd maintain a count of requests handled by each server and, at the end, identify the busiest servers.
Code (Python):
def busiest_servers_naive(k, arrival, load):
servers = [0] * k # 0 indicates available, time indicates busy until
counts = [0] * k
for i in range(len(arrival)):
start_server = i % k
assigned = False
for j in range(k):
server_index = (start_server + j) % k
if servers[server_index] <= arrival[i]:
servers[server_index] = arrival[i] + load[i]
counts[server_index] += 1
assigned = True
break
if not assigned:
pass #request dropped
max_count = max(counts)
busiest = [i for i, count in enumerate(counts) if count == max_count]
return busiest
Time Complexity: O(n*k), where n is the number of requests (length of arrival
) and k is the number of servers.
Space Complexity: O(k), for the servers
and counts
arrays.
To optimize, we can use a priority queue (min-heap) to keep track of available servers and their indices. We also use a sorted set to store the indices of servers that are currently processing requests and will become available in the future.
i % k
server.i % k
. If that server is available (its index is at the top of the min-heap), assign the task to it. If not, poll the available servers until we find one >= i % k
. If we reach the end, start at 0. If the available servers is empty, drop the request.Code (Python):
import heapq
from sortedcontainers import SortedSet
def busiest_servers(k, arrival, load):
available = list(range(k))
heapq.heapify(available)
busy = SortedSet()
counts = [0] * k
for i in range(len(arrival)):
while busy and busy[0][0] <= arrival[i]:
_, server_index = busy.pop(0)
heapq.heappush(available, server_index)
if not available:
continue
start_server = i % k
# Find the next available server index >= start_server
server_index = -1
temp_available = []
while available:
s = heapq.heappop(available)
if s >= start_server:
server_index = s
break
else:
temp_available.append(s)
# If no available server found >= start_server, take the smallest
if server_index == -1:
if temp_available:
server_index = temp_available.pop(0)
else:
continue #no available server
for s in temp_available:
heapq.heappush(available, s)
counts[server_index] += 1
busy.add((arrival[i] + load[i], server_index))
max_count = max(counts)
busiest = [i for i, count in enumerate(counts) if count == max_count]
return busiest
Time Complexity: O(n log k), where n is the number of requests and k is the number of servers. The heapq.heappush
and heapq.heappop
operations take O(log k) time, and in the worst case, we might perform these operations for each request.
Space Complexity: O(k), for the available
, busy
, and counts
arrays.