Сравнивая сложность O (n + m) и O (max (n, m))
Сегодня у меня было собеседование. И спросили о сложности std:set_intersection
. Когда я отвечал, я упомянул, что
О (п + т)
равно:
О (макс (п, т))
Мне сказали, что это неверно. Я безуспешно пытался показать эквивалентность:
O (0,5 * (n + m)) ≤ O (max (n, m)) ≤ O (n + m)
Мой вопрос: я действительно неверен?
Ответы
Ответ 1
Для всех m, n ≥ 0 справедливо, что max (m, n) ≤ m + n → max (m, n) в O (m + n) и m + n ≤ 2max (m, n) → m + n в O (max (m, n)).
Таким образом, O (max (m, n)) = O (m + n).
ДОБАВЛЕНИЕ. Если f принадлежит O (m + n), то существует константа D > 0, что f (n, m) < D * (m + n) для m и n достаточно больших. Таким образом, f (n, m) 2 D * max (m, n) и O (m + n) должны быть подмножеством O (max (m, n)). Доказательство O (max (m, n)) является подмножеством O (m + n) аналогичным образом.
Ответ 2
Хорошо, что вы полностью правы относительно O (n + m), равно O (max (n, m)), еще точнее мы можем доказать Θ (n + m) = Θ (max (n, m), который является более жестким и доказывает ваше предложение. Математическое доказательство (как для больших О, так и для Θ) очень просто и легко понять с здравым смыслом. Поэтому, поскольку у нас есть mathematical proof
, который является способом сказать что-то, но в более четко определенный и строгий способ, который doesn't leaves any ambiguity
.
Хотя вы (ошибочно) сказали, что это неверно, потому что, если мы хотим быть очень точными, это не является подходящим математическим способом выражения того, что порядок max (m, n) совпадает с m + n. Вы использовали слова "равно", ссылаясь на ноту "большой О", но каково определение нотации большого О?
Относится к Sets
. Высказывание max (n + m) принадлежит O (m + n) - это наиболее правильный путь и наоборот m + n принадлежит O (max (m, n)). В больших O обычно используется и принято считать m + n = O (max (n, m)).
Проблема заключается в том, что вы не пытались ссылаться на порядок функции, такой как f - O (g), но вы пытались сравнить Sets O (f) и O (g). Но доказательство двух бесконечных множеств равным нелегко (и это может смутить интервьюера).
Мы можем сказать, что наборы A и B идентичны (или равны), когда содержат одни и те же элементы (мы не пытаемся сравнивать, а вместо этого ссылаемся на элементы, которые они содержат, поэтому они должны быть конечными). И даже идентификация не может быть легко применена при разговоре о Big O Sets.
Big O of F используется для обозначения того, что мы говорим о наборе, который содержит все функции с порядком больше или равным F. Сколько функции есть?
Infinite since F+c is contained and c can take infinite values.
Как вы могли сказать, что два разных набора идентичны (или равны), когда они бесконечно, ну это не так просто.
So I understand what you are thinking that n+m and max(n,m) have same
order but **the right way to express that** is by saying n+m is
O(max(n,m)) and max(n,m)is O(m+n) ( O(m+n) is equal to O(max(m,n))
may better requires a proof).
Еще одна вещь, мы сказали, что эти функции имеют одинаковый порядок, и это абсолютно математически правильно, но при попытке сделать оптимизацию алгоритма вам может потребоваться учитывать некоторые факторы нижнего порядка, возможно, они дают вам несколько разные результаты но асимптотическое поведение оказывается одинаковым.
Заключение
Как вы можете прочитать в wikipedia (и во всех курсах cs в каждом университете или в каждой книге алгоритмов) Big O/θ/Ω/ω/ο обозначений helps us compare functions
и найти их порядок роста, а не для множеств функций, и именно поэтому вам сказали, что вы ошибаетесь. Хотя легко сказать, что O (n ^ 2) является подмножеством O (n), очень сложно сравнивать бесконечное, если сказать, что два набора идентичны. Кантор работал над категоризацией бесконечных множеств, например, мы знаем, что натуральные числа счетны бесконечно, а вещественные числа бесчисленны бесконечно, поэтому действительные числа больше натуральных чисел, хотя оба они бесконечны. Это становится очень сложным, когда вы пытаетесь упорядочить и классифицировать бесконечные множества, и это будет скорее исследование в математике, чем способ сравнения функций.
UPDATE
Оказывается, вы можете просто доказать, что O (n + m) равно O (max (n, m)):
для каждой функции F, принадлежащей O (n + m), это означает, что существуют константы c и k такие:
F <= c(n+m) for every n>=k and m>=k
то также стоит:
F <= c(n+m)<= 2c*max(n,m)
так что F принадлежит O (max (n, m)), и в результате O (m + n) является подмножеством O (max (n, m)).
Теперь рассмотрим, что F принадлежит O (max (n, m)), то существуют константы c и k такие:
F <= c*max(n+m) for every n>=k and m>=k
и мы также имеем:
F <= c*max(n+m)<=2c(m+n) for every n>=k and m>=k
поэтому c '= 2c и с тем же k по определению: F равно O (m + n), и в результате O (max (n, m)) является подмножеством O (n + m). Поскольку мы доказали, что O (m + n) является подмножеством O (max (n, m)), мы доказали, что O (max (m, n)) и O (m + n) равны strong > , и это математическое доказательство доказывает, что вы совершенно правы, без всяких сомнений.
Наконец, отметим, что , доказывающее, что m + n равно O (max (n, m)), а max (n, m) - O (m + n), не сразу доказывает, что множества равны (для этого нам нужно доказательство), так как вы говорите, что это просто доказывает, что функции имеют одинаковый порядок, но мы не рассматривали множества. Хотя легко видеть (в общем случае), что если f есть O (g), а g - O (F), то вы можете легко доказать, что в этом случае большой O устанавливает равенство, как в предыдущем абзаце.
Ответ 3
Мы продемонстрируем строгим анализом Big-O, что вы действительно правы, учитывая один возможный выбор параметра роста в вашем анализе. Однако это не обязательно означает, что точка зрения интервьюера неверна, а его выбор параметра роста отличается. Тем не менее, его/ее запрос о том, что ваш ответ был совершенно неправильным, вызывает сомнения: вы, возможно, просто использовали два немного разных подхода к анализу асимптотической сложности std::set_intersection
, что приводит к общему мнению о том, что алгоритм работает в линейном времени.
Подготовка
Давайте начнем с рассмотрения ссылки std::set_intersection
на cppreference (выделение)
Параметры
first1
, last1
- первый диапазон элементов для изучения
first2
, last2
- второй диапазон элементов для изучения
Сложность
Не более 2·(N1+N2-1)
сравнений, где
N1 = std::distance(first1, last1)
N2 = std::distance(first2, last2)
std::distance
сам по себе является линейным (наихудший случай: без произвольного доступа)
std::distance
...
Возвращает количество элементов между first
и last
.
Перейдем к краткому изложению основ нотации Big-O.
Обозначение Big-O
Мы слабо сформулируем определение функции или алгоритма f
в O(g(n))
(быть разборчивым, O(g(n))
является набором функций, а значит, f ∈ O(...)
, а не обычным образом использованным f(n) ∈ O(...)
).
Если функция f
находится в O(g(n))
, то c · g(n)
является верхней связанный на f(n)
, для некоторой неотрицательной константы c
такой, что f(n) ≤ c · g(n)
при достаточно больших n
(т.е. n ≥ n0
для некоторой постоянной n0
).
Следовательно, чтобы показать, что f ∈ O(g(n))
, нам нужно найти набор (неотрицательных) констант (c, n0)
, который выполняет
f(n) ≤ c · g(n), for all n ≥ n0, (+)
Заметим, однако, что это множество не является уникальным; задача нахождения констант (c, n0)
такая, что (+) имеет место, вырождается. На самом деле, если любая такая пара констант существует, будет существовать бесконечное количество различных таких пар.
Мы продолжаем анализ Big-O std::set_intersection
, основанный на уже известном наихудшем числе сравнений алгоритма (мы рассмотрим одно такое сравнение как базовую операцию).
Применение асимптотического анализа Big-O к примеру set_intersection
Теперь рассмотрим два диапазона элементов, например range1
и range2
, и предположим, что количество элементов, содержащихся в этих двух диапазонах, равно m
и n
соответственно.
- Обратите внимание! Уже на этом начальном этапе анализа мы делаем выбор: мы решили изучить проблему в терминах двух разных параметров роста (точнее, сосредоточившись на наибольшей из этих двух). Как мы увидим дальше, это приведет к той же асимптотической сложности, что и заявленная ОП. Однако мы могли бы также выбрать, чтобы
k = m+n
был выбранным параметром: мы бы все же пришли к выводу, что std::set_intersection
имеет сложность линейного времени, а скорее в терминах k
(которая m+n
который не max(m, n)
), чем самый большой из m
и n
. Это просто предпосылки, которые мы свободно выбираем, прежде чем приступать к нашей нотации/асимптотическому анализу Big-O, и вполне возможно, что интервьюер предпочитал анализировать сложность, используя k
как параметр роста, а не самый большой из двух его компонентов.
Теперь, сверху, мы знаем, что в худшем случае std::set_intersection
будет запускать 2 · (m + n - 1)
сравнения/базовые операции. Пусть
h(n, m) = 2 · (m + n - 1)
Поскольку цель состоит в том, чтобы найти выражение асимптотической сложности в терминах Big-O (верхняя граница), мы можем, не ограничивая общности, считать, что n > m
и определить
f(n) = 2 · (n + n - 1) = 4n - 2 > h(n,m) (*)
Перейдем к анализу асимптотической сложности f(n)
в терминах записи Big-O. Пусть
g(n) = n
и заметим, что
f(n) = 4n - 2 < 4n = 4 · g(n)
Теперь (выберите) пусть c = 4
и n0 = 1
, и мы можем констатировать тот факт, что:
f(n) < 4 · g(n) = c · g(n), for all n ≥ n0, (**)
Учитывая (**)
, из (+)
известно, что мы теперь показали, что
f ∈ O(g(n)) = O(n)
Кроме того, поскольку `(*) выполняется, естественно
h ∈ O(g(n)) = O(n), assuming n > m (i)
имеет место.
Если мы переключим наше первоначальное предположение и предположим, что m > n
, повторное отслеживание проведенного выше анализа, наоборот, даст аналогичный результат
h ∈ O(g(m)) = O(m), assuming m > n (ii)
Заключение
Следовательно, учитывая два диапазона range1
и range2
, удерживающие элементы m
и n
, соответственно, мы показали, что асимптотическая сложность std::set_intersection
применяется двумя этими двумя диапазонами действительно
O(max(m, n))
где мы выбрали наибольший из m
и n
как параметр роста нашего анализа.
Это, однако, не очень достоверная аннотация (по крайней мере, не обычная), когда речь идет о записи Big-O. Когда мы используем обозначение Big-O для описания асимптотической сложности какого-либо алгоритма или функции, мы делаем это в отношении одного единственного параметра роста (а не из двух).
Вместо того, чтобы отвечать на то, что сложность O(max(m, n))
, мы можем без ограничения общности предположить, что n
описывает количество элементов в диапазоне с большинством элементов и при условии, что это предположение просто определяется, чем верхняя граница для асимптотической сложности std::set_intersection
есть O(n)
(линейное время).
Предположения о обратной связи с интервью: как упоминалось выше, возможно, что у интервьюера просто было твердое представление о том, что нотация/асимптотический анализ Big-O должна была основываться на k = m+n
как на параметре роста, самый большой из двух его компонентов. Другой возможностью, естественно, было то, что интервьюер просто смущенно спросил о худшем случае фактического количества сравнений std::set_intersection
, смешивая это с отдельным вопросом нотации Big-O и асимптотической сложностью.
Заключительные замечания
Наконец, отметим, что анализ сложности худшего случая std::set_intersect
вовсе не является репрезентативным для широко изученной проблемы с неупорядоченным множеством пересечений: первый применяется к диапазонам, которые уже отсортированы (см. цитату из Boost set_intersection
ниже: происхождение std::set_intersection
), тогда как в последнем мы изучаем вычисление пересечения неупорядоченных наборов.
Описание
set_intersection
строит отсортированный диапазон, являющийся пересечением из отсортированных диапазонов rng1
и rng2
. Возвращаемое значение конец выходного диапазона.
В качестве примера последнего метод set Intersection
для Python применяется к не упорядоченным наборам и применяется к словам наборов s
и t
, имеет средний случай и худшую сложность O(min(len(s), len(t))
и O(len(s) * len(t))
соответственно. Огромное различие между средним и худшим случаем в этой реализации связано с тем, что решения на основе хэшей на практике, как правило, очень хорошо работают на практике, но для некоторых приложений теоретически могут иметь очень плохие результаты в наихудшем случае.
Дополнительные сведения о последней проблеме см., например,