У меня есть функция, которая принимает число n
, обозначающее количество серверов, а другой параметр представляет список requests
.
Первоначально серверы будут хранить значения 0 размера n
.
Для каждого запроса requests[i]
найдите индекс сервера, который имеет минимальное значение в диапазоне [0, requests[i]]
, сохраните этот индекс в результате, а также увеличьте значение на единицу для этого индекса сервера. Если несколько серверов имеют одинаковый минимум в диапазоне [0, requests[i]]
, выберите тот, у которого позиция индекса меньше.
Пример:
n = 5 and requests = [3, 2, 3, 2, 4]
Результат :
[0,1,2,0,3]
Объяснение:
a) requests[0] = 3
n=5 so servers = [0,0,0,0,0]
pick server that has minimum value in range [0, request[0]] = [0,3], the servers in range [0,3] are [0,0,0]
pick server at index 0, and store it in result = [0]. also increment server[0]++ so servers array is now [1,0,0,0,0]
b) requests[1] = 2
servers = [1,0,0,0,0]
pick server that has minimum value in range [0, request[1]] = [0,2], the servers in range [0,2] are [1,0,0]
pick server at index 1, and store it in result = [0, 1]. also increment server[1]++ so servers array is now [1,1,0,0,0]
c) requests[2] = 3
servers[1,1,0,0,0]
range [0,3] => [1,1,0,0]
pick server at index 2, so result = [0,1,2], now servers = [1,1,1,0,0]
d) requests[3] = 2
servers[1,1,1,0,0]
range [0,2] => [1,1,1]
pick server at index 0, so result = [0,1,2, 0], now servers = [2,1,1,0,0]
e) requests[4] = 4
servers[2,1,0,0,0]
range [0,4] => [2,1,1,0,0]
pick server at index 3, so result = [0,1,2,0, 3], now servers = [2,1,1,1,0]
Finally result is [0, 1,2,0,3]
Ограничения:
1 <= n <= 10^5
0 <= requests[i] < n
Вот мой код с временной сложностью O(n^2)
import java.util.*;
public class Main {
public static void main(String[] args) {
System.out.println(solve(5, Arrays.asList(3,2,3,2, 4))); //[0,1,2,0,3]
}
public static List<Integer> solve(int n, List<Integer> requests) {
int[] servers = new int[n];
List<Integer> result = new ArrayList<>();
for (int e : requests) {
int min = Integer.MAX_VALUE;
int idx = -1;
for (int i = 0; i <= e; i++) {
if (servers[i] < min) {
min = servers[i];
idx = i;
}
}
result.add(idx);
servers[idx]++;
}
return result;
}
}
Как решить эту проблему за меньшее время?
«Серверы в диапазоне [0,3] — [0,0,0]» — «Серверы в диапазоне [0,2] — [1,0,0]» — Почему они одинаковой длины?
Ваш код не O(n^2), так как время выполнения зависит от количества запросов, которое не ограничено.
Эту проблему можно решить, используя дерево сегментов, в котором хранится наименьший индекс минимального значения в каждом узле. Обновления и запросы — это O(log N)
.
Кажется медленным и сложным :-P
@nocomment У большинства людей, занимающихся соревновательным программированием, в любом случае есть удобный шаблон дерева сегментов, так что на самом деле это путь с минимальными усилиями. :)
Хм, возможно. Я думаю, что это могло измениться с тех пор, как я был активен. Но все равно медленнее, я думаю.
O(n+r), где r — количество запросов.
Обратите внимание, что servers
монотонно убывает. Таким образом, для каждого запроса e минимальное значение в servers[0..e]
— это значение servers[e]
. Нам просто нужно найти первый индекс, в котором встречается это значение. Для этого мы отслеживаем первый индекс для каждого встречающегося значения. Попробуйте это онлайн!
public static List<Integer> solve(int n, List<Integer> requests) {
int[] servers = new int[n];
int[] first = new int[requests.size()];
List<Integer> result = new ArrayList<>();
for (int e : requests) {
int min = servers[e];
int idx = first[min++]++;
result.add(idx);
servers[idx]++;
if (idx == 0 || servers[idx-1] > min)
first[min] = idx;
}
return result;
}
Версия Python с более масштабным тестом (n=1000 и r=10000, сравнение результата с наивным решением):
def solve_fast(n, requests):
servers = [0] * n
first = {0: 0}
result = []
for r in requests:
s = servers[r]
i = first[s]
result.append(i)
servers[i] += 1
first[s] += 1
if i == 0 or servers[i-1] > s+1:
first[s+1] = i
return result
def solve_naive(n, requests):
servers = [0] * n
result = []
for r in requests:
s = min(servers[:r+1])
i = servers.index(s)
result.append(i)
servers[i] += 1
return result
import random
def test(n, requests):
expect = solve_naive(n, requests)
result = solve_fast(n, requests)
print(result == expect)
print(str(expect)[-80:])
print(str(result)[-80:])
print()
n = 5
requests = [3, 2, 3, 2, 4]
test(n, requests)
n = 1000
requests = random. choices(range(n), k=n*10)
test(n, requests)
Пример вывода (Попробуйте это онлайн!):
True
[0, 1, 2, 0, 3]
[0, 1, 2, 0, 3]
True
, 125, 937, 202, 421, 38, 310, 543, 874, 782, 311, 544, 875, 126, 783, 312, 203]
, 125, 937, 202, 421, 38, 310, 543, 874, 782, 311, 544, 875, 126, 783, 312, 203]
Если данные не отсортированы заранее, вам придется отсканировать их полностью. Но обязательно ли использовать вложенные циклы? Если вы можете сделать это за один проход, у вас будет O(n).