Общая идея нотации big-O такова: она дает грубый ответ на вопрос: «Если вам дан набор из N элементов, и вам необходимо выполнить какую-либо операцию над этими элементами, сколько раз будет вам нужно выполнить эту операцию? Я говорю грубый ответ, потому что он (в большинстве случаев) не дает точного ответа «5 * N + 35», а просто «N». Это как стадион. Точный ответ вас не волнует, вы просто хотите знать, насколько плохо будет, когда N станет большим. Поэтому ответы типа O (N), O (N * N), O (logN) и O (N!) Являются типичными, поскольку каждый из них представляет собой своего рода «класс» ответов, которые вы можете сравнить друг с другом. Алгоритм с O (N) будет работать лучше, чем алгоритм с O (N * N), когда N становится достаточно большим, не имеет значения, насколько длительной является сама операция.
Итак, я разбил его так: сначала определите, каким будет N. В приведенных выше примерах это довольно очевидно - это размер входного массива, потому что он определяет, сколько раз мы будем выполнять цикл. Иногда это не так очевидно, а иногда у вас есть несколько входных данных, поэтому вместо просто N вы также получаете M и другие буквы (и тогда ответом будет что-то вроде O (N * M * M)).
Затем, когда я вычислил N, я пытаюсь определить цикл, который зависит от N. На самом деле, эти две вещи часто идентифицируются вместе, так как они в значительной степени связаны друг с другом.
И, наконец, мне нужно выяснить, сколько итераций программа выполнит в зависимости от N. И чтобы упростить задачу, я не пытаюсь их подсчитать, просто пытаюсь распознать типичные ответы - O (1), O (N), O (N * N), O (logN), O (N!) Или, возможно, некоторая другая степень N. O (N!) На самом деле довольно редкий, потому что он настолько неэффективен, что его реализация была бы бессмысленной.
Если вы получите ответ на что-то вроде N * N + N + 1, просто отбросьте меньшие, потому что, опять же, когда N становится большим, остальные больше не имеют значения. И игнорировать, если операция повторяется некоторое фиксированное количество раз. O (5 * N) - это то же самое, что O (N), потому что мы ищем приблизительный уровень.
Добавлено: Как указано в комментариях, вот анализ первых двух методов:
Первый прост. Есть только две петли, внутренняя - O (N), а внешняя просто повторяет это 3 раза. Так что это все еще O (N). (Помните - O (3N) = O (N)).
Второй хитрый. Я не совсем уверен в этом. Посмотрев на него некоторое время, я понял, почему он зацикливается не более 50 раз. Поскольку это вообще не зависит от N, оно считается как O (1). Тем не менее, если вы передадите его, скажем, массив из 10 элементов, все положительные, он будет идти в бесконечном цикле. Это O (∞), я думаю. Так какой это? Я не знаю ...
Я не думаю, что есть формальный способ определения числа биг-О для алгоритма. Это как проблема остановки. На самом деле, если подумать, если бы вы могли универсально определить big-O для фрагмента кода, вы также можете определить, останавливается ли он когда-либо или нет, что противоречит проблеме остановки. Но это только мои размышления.
Как правило, я просто проходил мимо ... не знаю, что-то вроде "чутья". Как только вы «получаете» то, что представляет Big-O, оно становится довольно интуитивным. Но для сложных алгоритмов это не всегда возможно определить. Взять, например, Quicksort. В среднем это O (N * logN), но в зависимости от данных оно может ухудшиться до O (N * N). На вопросы, которые вы получите на экзамене, должны быть четкие ответы.