Кто-то разместил этот вопрос здесь несколько недель назад, но он выглядел ужасно, как домашнее задание без предварительного исследования, и ОП быстро удалил его после получения нескольких downvotes.
Сам вопрос был довольно интересным, и я думал об этом неделю, не найдя удовлетворительного решения. Надеюсь, кто-то может помочь?
Вопрос заключается в следующем: задает список из N целых интервалов, границы которых могут принимать любые значения от 0
до N³
, найти наименьшее целое число i
такое, что i
не принадлежит на любой из входных интервалов.
Например, если задан список [3,5] [2,8] [0,3] [10,13]
(N = 4), алгоритм должен возвращать 9
.
Самое простое решение, о котором я могу думать, работает в O(n log(n))
и состоит из трех шагов:
- Сортировка интервалов путем увеличения нижней границы
-
- Если наименьшая нижняя границa > 0, верните 0;
- В противном случае повторно слияние первого интервала со вторым, пока первый интервал (скажем
[a, b]
) не коснется второго (скажем[c, d]
) - то есть до тех пор, пока b + 1 < c, или пока не будет только один интервал.
- Возврат
b + 1
Это простое решение работает в O(n log(n))
, но исходный плакат написал, что алгоритм должен работать в O(n)
.. Это тривиально, если интервалы уже отсортированы, но пример, который дал OP включая несортированные интервалы. Я предполагаю, что это должно иметь какое-то отношение к N³
bound, но я не уверен, что... Хеширование? Линейная сортировка времени? Идеи приветствуются.
Ниже приведена грубая реализация python для алгоритма, описанного выше:
def merge(first, second):
(a, b), (c, d) = first, second
if c <= b + 1:
return (a, max(b, d))
else:
return False
def smallest_available_integer(intervals):
# Sort in reverse order so that push/pop operations are fast
intervals.sort(reverse = True)
if (intervals == [] or intervals[-1][0] > 0):
return 0
while len(intervals) > 1:
first = intervals.pop()
second = intervals.pop()
merged = merge(first, second)
if merged:
print("Merged", first, "with", second, " -> ", merged)
intervals.append(merged)
else:
print(first, "cannot be merged with", second)
return first[1] + 1
print(smallest_available_integer([(3,5), (2,8), (0,3), (10,13)]))
Вывод:
Merged (0, 3) with (2, 8) -> (0, 8)
Merged (0, 8) with (3, 5) -> (0, 8)
(0, 8) cannot be merged with (10, 13)
9