Алгоритмическая интуиция для логарифмической сложности

60

Я считаю, что у меня есть разумное представление о сложностях, таких как , Θ ( n ) и Θ ( n 2 )O(1)Θ(n)Θ(n2) .

С точки зрения списка, - это постоянный поиск, поэтому он просто получает заголовок списка. Θ ( n ) - это место, где я прошёл бы весь список, а Θ ( n 2 ) - список по одному разу для каждого элемента в списке.O(1)Θ(n)Θ(n2)

Есть подобный интуитивный способ понять , кроме просто зная , что лежит где - то между O ( 1 ) и & thetas ( п ) ?Θ(logn)O(1)Θ(n)

Khanzor
источник
8
log n предназначен для «поиска»: подумайте о бинарном поиске
Suresh
2
Использование чтобы задать этот вопрос неверно, так как оно обозначает только верхнюю границу. Например, постоянное время O ( log n ) . θ будет более уместным. См. Мета-вопрос: meta.cs.stackexchange.com/questions/182/…OO(logn)θ
Арьябхата
1
Больше информации о SO: что означает ? O(logn),
Ран Г.
Небольшое примечание: в классических настройках машины Тьюринга все алгоритмы имеют , так как они должны прочитать каждый символ ввода хотя бы один раз. Двоичный поиск может быть выполнен в O ( log n ), потому что у нас есть обещание, что список отсортирован, например. Ω(n)O(logn)
chazisop
1
Поздний вклад: по определению, основной логарифм числа n - это просто количество раз, которое вы умножили b на себя, чтобы получить n . b l = nbnbn . Например, 2 3 = 8bl=nl=logb(n) . Так что, если у вас есть номер n, и вы хотите узнать, что l o g b ( n ) = ? просто продолжайте делить его на b, пока не достигнете 1 (предполагая, что n - это степень b для простоты). Количество делений равно l o g b ( n ) . Алгоритмы, демонстрирующие такое поведение деления, имеют время выполнения в O ( l o g23=8log2(8)=3nlogb(n)=?b1nblogb(n) . O(log(n))
saadtaame

Ответы:

54

сложность, как правило , связаны с подразделением. При использовании списков в качестве примера представьте список, элементы которого отсортированы. Вы можете искать в этом списке в O ( log n )Θ(logn)O(logn) - вам не нужно просматривать каждый элемент из-за отсортированной природы списка.

Если вы посмотрите на элемент в середине списка и сравните его с элементом, который вы ищете, вы можете сразу сказать, находится ли он в левой или правой половине массива. Затем вы можете просто взять эту половину и повторять процедуру, пока не найдете ее или не достигнете списка с 1 элементом, который вы тривиально сравниваете.

Вы можете видеть, что список фактически делит пополам каждый шаг. Это означает, что если вы получите список длиной , то максимальное количество шагов, которое вам нужно для достижения списка из одного элемента, равно 5 . Если у вас список 128 = 2 7 элементов, вам нужно всего 7 шагов, для списка 1024 = 2 10 вам нужно всего 10 шагов и т. Д.325128=2771024=21010

Как вы можете видеть, показатель степени в 2 n всегда показывает количество необходимых шагов. Логарифм используется для «извлечения» именно этого числа экспоненты, например, log 2 2 10 = 10 . Он также обобщает список длин, которые не являются степенями двух длин.n2nlog2210=10

Карел Петранек
источник
4
Следует отметить, что это только в том O(log n)случае, если список имеет постоянное время произвольного доступа. В более типичных реализациях списков (связанных списков) этоO(n log n)
asm
1
Бинарный поиск не работает в списках из-за отсутствия указателей; обычно это делается на массивах.
Рафаэль
Двоичный поиск прекрасно работает в списках. Это просто бессмысленно из-за того, что намного сложнее, чем требуется / полезно / практично.
Антон
@AndrewMyers Более точный поиск в связанном списке O(n)
phant0m
1
@ phant0m Да, мне понадобилось немного времени, чтобы понять, что вы предполагаете, что вы перемещаетесь из текущей позиции, а не перемещаетесь с самого начала каждый раз.
Asm
38

В терминах (сбалансированных) деревьев (скажем, двоичного дерева, так что все - это база 2):log

  • получает корень дереваΘ(1)
  • - это путь от корня к листуΘ(logn)
  • пересекает все узлы дереваΘ(n)
  • - действия на всех подмножествах двух узлов в дереве, например, количество различных путей между любыми двумя узлами.Θ(n2)
  • - обобщение приведенного выше для любого подмножества k узлов (для константы k )Θ(nk)kk
  • - действия над всеми возможными подмножествами узлов (подмножествами всех возможных размеров, т. Е. K = 1 , 2 , , n .). Например, количество различныхподдеревьевдерева.Θ(2n)k=1,2,,n
Ран Г.
источник
5
Чтобы добавить к этому, интуиция для происходит от двух вещей: 1.) Повторение T ( n ) = T ( Θ(loglogn) и 2.) Бинарный поиск по чему-либо размером l o g ( n ), т.е. бинарный поиск по высоте дерева. T(n)=T((n))+1log(n)
Mcorley
17

Чтобы было возможно, вам нужно уметь пропорционально сократить размер задачи на некоторую произвольную величину по отношению к n с помощью операции с постоянным временем.O(logn)n

Например, в случае бинарного поиска вы можете сократить размер задачи вдвое при каждой операции сравнения.

Теперь вы должны сократить размер проблемы вдвое, на самом деле нет. Алгоритм - это даже если он может сократить пространство поиска проблемы на 0,0001%, при условии, что процент и операция, используемая для сокращения размера проблемы, остаются постоянными, это O ( log nO(logn)алгоритм ) , это не будет быстрый алгоритм, но он все равно O ( log n ) с очень большой константой. (Предполагается, что мы говорим о log n с журналом base 2)O(logn)O(logn)logn

Кен Ли
источник
1
Что было бы, если бы «количество вырубки» не было постоянным?
Свиш
@Svish Если вы можете сократить проблему с положительной скоростью, это все равно будет алгоритм , хотя, вероятно, он уже не будет жестким ограничением. Отрицательный показатель сложно сказать. В этом случае было сделано предположение, чтобы сделать ответ довольно простым, поскольку у этого вопроса есть свои достоинства, вы можете задать его как вопрос самостоятельно. O(logn)
Кен Ли
Да, я имел в виду, что пространство поиска проблем всегда уменьшалось, но не обязательно с постоянной скоростью. Я просто думал о том, что «до тех пор, пока процент и операция, используемая для сокращения размера проблемы, остаются постоянными, это алгоритм O (log n)»; если бы он имел другое имя, если процент не был постоянным.
Свиш
8

Подумайте об алгоритме преобразования десятичного числа в двоичноеn

while n != 0:
   print n%2, 
   n = n/2

Этот whileцикл запускает раз.log(n)

Пратик Деогхаре
источник
1
Конечно, эта программа зацикливает раз, но обычно, когда мы говорим о сложности O ( f ( s ) ) , s - это размер вашего ввода. Здесь размер вашего ввода уже s = log n , поэтому я бы сказал, что эта программа только линейная (в O ( s ) )lognO(f(s))ss=lognO(s)
jmad
@jmad Верно. Но этот пример дает вам интуицию в log (n).
Pratik Deoghare
@jmad Я мог бы использовать алгоритм для генерации случайных чисел, но я хотел, чтобы это было как можно проще.
Pratik Deoghare
8

Да, находится между 1 и n , но ближе к 1, чем n . Что такое log ( n ) ? Лог-функция является обратной функцией экспоненты. Позвольте мне начать с экспоненты, и вы должны лучше понять, что такое логарифм.log(n)1n1nlog(n)

Рассмотрим два числа, и 2 100 . 2 100 - это 2, умноженные на себя в 100 раз. Вы можете с некоторым усилием сосчитать 100 чисел, но можете ли вы сосчитать 2 100 ? Бьюсь об заклад, вы не можете. Почему? 2 100 такое большое число, что оно больше, чем число всех атомов во вселенной. Задумайтесь об этом на мгновение. Это настолько большое число, что оно позволяет дать каждому атому имя (число). А количество атомов в ногтях у вас, вероятно, порядка миллиардов. 2 100100210021002100100210021002100 должно быть достаточно для всех (каламбур предназначен).

Теперь между двумя числами, и 2 100 , 100 - логарифм 2 100 (в базе 2 ). 100 сравнительно такое небольшое число, чем 2 100 . У кого угодно должно быть 100 разных предметов в своем доме. Но 2 100 достаточно хорошо для вселенной. Думай домой против вселенной, думая о журнале ( n )10021001002100210021001002100log(n) и n .

Откуда взялись экспонента и логарифмы? Почему они так интересуются информатикой? Вы можете не заметить, но экспонента повсюду. Вы платили проценты по кредитной карте? Вы только что заплатили вселенную за свой дом (не так уж плохо, но кривая подходит). Мне нравится думать, что экспонента исходит из правила продукта, но другие могут привести больше примеров. Вы можете спросить, какое правило продукта? И я отвечу.

Скажем, у вас есть два города и B , и между ними есть два пути. Какое количество путей между ними? Два. Это тривиально. Теперь, скажем, есть другой город C , и вы можете перейти от B к C тремя способами. Сколько сейчас путей между А и С ? Шесть, верно? Как ты это получил? Вы их посчитали? Или ты их умножил? В любом случае, легко увидеть, что оба способа дают одинаковый результат. Теперь, если вы добавите город D, до которого можно добраться из C четырьмя способами, сколько будет путей между A ? Посчитайте, если вы мне не доверяете, но оно равно 2 ABCBCACDCA и D есть 24 . Теперь, если есть десять городов и есть два пути из одного города в другой, и они расположены так, как будто они находятся на прямой линии. Сколько путей существует от начала до конца? Умножьте их, если вы мне не доверяете, но я скажу вам, что есть 2 10 , то есть 1024 . Смотрите, что 2 10 - это экспоненциальный результат 10 , а 10 - логарифм 2 10 . 10 - небольшое число по сравнению с 1024 .2342421010242101010210101024

Функция логарифма равна n, что n равно 2 n (обратите внимание, что 2 - это основание логарифма). Если вы умножаете log b ( n ) на себя b раз (обратите внимание, что b - это основание логарифма), вы получите n . log ( n ) настолько мал, настолько мал по сравнению с n , что это размер вашего дома, где n - это размер вселенной.log2(n)nn2n2logb(n)bbnlog(n)nn

На практике заметим, что функции очень похожи на функции констант. Они растут с п , но они растут очень медленно. Если вы оптимизировали программу для выполнения в логарифмическом времени, которое занимало день раньше, вы, вероятно, запустите ее в течение нескольких минут. Проверьте сами проблемы с Project Euler.log(n)n

Ravi
источник
3
Несмотря на то, что этот ответ хорошо написан, в нем практически нет информации, кроме « действительно маленький»). log(n)
Рафаэль
3
Я пытался дать интуицию о том, как это мало.
Рави
5

Чтобы продолжить вашу тему, равно что гадать где хO(logn)x лежит в списке, и ему говорят «выше» или «ниже» (в терминах индекса).

Он по-прежнему зависит от размера списка, но вам нужно посетить только часть элементов.

dpatchery
источник
4

Если у нас есть алгоритм «разделяй и властвуй» , и мы делаем только один рекурсивный вызов для подзадачи, и это второй случай в теореме Мастера , т. Е. Временная сложность нерекурсивной части равна , то сложность алгоритма составит Θ ( lg k + 1 n )Θ(lgkn)Θ(lgk+1n) .

Другими словами, когда у нас есть алгоритм «разделяй и властвуй» с одним рекурсивным вызовом к себе для задачи с размером, постоянным множителем текущей задачи, и время в нерекурсивной части равно (постоянная), тогда время работы алгоритма будет lg nΘ(1)lgn .

Бинарный поиск алгоритм является классическим примером.

Кава
источник
1

Интуиция заключается в том, сколько раз вы можете вдвое уменьшить число, скажем, n, прежде чем оно уменьшится до 1 - O (lg n).

Для визуализации попробуйте нарисовать его в виде бинарного дерева и подсчитать количество уровней, решив эту геометрическую прогрессию.

2^0+2^1+...+2^h = n
user1234
источник
Добро пожаловать на сайт! То, что вы говорите, конечно, правда, но я не вижу, что это добавляет к существующим ответам. В некоторых из ответов уже сказано, что логарифм - это количество раз, которое вы можете разделить на два, прежде чем нажать 1, а в ответе Рана уже сказано, что - это высота двоичного дерева с n листьями. lognn
Дэвид Ричерби