Вариант DNF выглядит следующим образом:
def dutch_flag_partition(pivot_index , A):
pivot = A[pivot_index]
# First pass: group elements smaller than pivot.
for i in range(len(A)):
# Look for a smaller element.
for j in range(i + 1, len(A)):
if A[j] < pivot:
A[i], A[j] = A[j], A[i]
break
# Second pass: group elements larger than pivot.
for i in reversed(range(len(A))):
if A[i] < pivot:
break
# Look for a larger element. Stop when we reach an element less than
# pivot , since first pass has moved them to the start of A.
for j in reversed(range(i)):
if A[j] > pivot:
A[i], A[j] = A[j], A[i]
break
Дополнительная пространственная сложность задается как O (1). Это связано с тем, что обмен не зависит от входной длины? И временная сложность, заданная как O (N ^ 2), так ли это из-за вложенных циклов? Спасибо
Дополнительная пространственная сложность задается как O (1). Это связано с тем, что обмен не зависит от входной длины?
Нет. Перестановка на самом деле вообще не занимает лишнего места.
Что еще более важно, вы не можете просто искать одну вещь и сказать, сколько всего этого требует, что сложность. Вы должны просмотреть все вещи, и самый большой определяет сложность. Итак, просмотрите все, что вы создаете:
pivot
- это просто ссылка на один из членов списка, который является постоянным размером.range
- это постоянный размер.range
является постоянным.i
и j
целые значения, возвращаемые итератором диапазона, являются постоянными. 1Поскольку размер ничего больше, чем постоянный, общий размер является постоянным.
И временная сложность, заданная как O (N ^ 2), так ли это из-за вложенных циклов?
Ну, да, но вам нужно получить более подробную информацию. Две вложенные циклы не обязательно означают квадратичные. Две вложенные циклы, которые выполняют линейную работу внутри вложенного цикла, будут кубическими. Две вложенные циклы, которые объединяются так, что размер внутреннего контура обратно зависит от внешнего контура, являются линейными. И так далее.
И снова вам нужно все добавить, а не просто выбрать одну вещь и угадать.
Итак, первый проход:
Итак, если break
вообще не помогает, то O(1 + N * N * 1)
, что является O(N * N)
.
Второй проход аналогичен O(N * (1 + N * 1))
, что опять O(N * N)
.
И если вы добавите O(N * N + N * N)
, вы получите O(N * N)
.
Кроме того, даже если break
сделал первый проход логарифмически линейным или что-то еще, O(N * log N + N * N)
все еще O(N * N)
, так что это не имеет значения.
Итак, время квадратично.
1. Технически это не совсем так.Целые числа имеют переменный размер, а память, которую они берут, - это журнал их величины.Итак, i
и j
, и атрибуты stop
объектов range
, и, вероятно, некоторые другие вещи - это все log N
Но, если вы не имеете дело с арифметикой огромного числа, например, в криптоалгоритмах, которые умножают огромные основные факторы, люди обычно игнорируют это и избегают этого.
Дополнительная пространственная сложность задается как O (1). Это связано с тем, что обмен не зависит от входной длины?
Поскольку вы "просто" заменяете, нет новых данных, которые создаются или генерируются, вы просто переназначаете уже имеющиеся значения, поэтому сложность пространства постоянна.
И временная сложность, заданная как O (N ^ 2), так ли это из-за вложенных циклов?
Правда. Это временная сложность полинома второго порядка, потому что у вас есть два для вложенных циклов.
У вас есть break
в них, поэтому в более благоприятных случаях ваша временная сложность будет ниже N ^ 2. Однако, поскольку большой-O - худший случай, тогда это нормально сказать это степени 2.
pivot
,range
и его итератор,i
и т. Д. - и все они, очевидно, постоянны. (Если это не Python 2, в этом случае эти диапазоны линейны ...)