Можно ли найти все мельчайшие элементы в списке за O(n) время?

#list #algorithm #time-complexity #big-o

Вопрос:

Предположим, у меня есть несортированный список, такой как приведенный ниже:

 [1, 2, 3, 1, 1, 5, 2, 1]
 

и я хочу вернуть количество минимальных элементов (в данном случае min = 1), которое равно 4.

Быстрое решение состоит в том, чтобы просто найти минимум, используя какую-либо встроенную min() функцию, а затем снова повторить список и сравнить значения, а затем подсчитать их. O(2n) время.

Но мне интересно, можно ли сделать это строго O(n) вовремя — сделать только один проход по списку. Есть ли способ сделать это?

Комментарии:

1. O(n) и O(2n) — это одно и то же.

Ответ №1:

Помните, что обозначение big-O говорит о том, как масштабируется среда выполнения, а не об абсолютной среде выполнения. В этом смысле алгоритм, который выполняет два прохода по массиву, каждый из которых занимает время O(n), также имеет время выполнения O(n) — время выполнения будет линейно масштабироваться по мере увеличения размера входных данных. Так что ваш двухпроходный алгоритм будет работать просто отлично.

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

  • если это значение больше, чем самое маленькое, которое вы видели, игнорируйте его;
  • если это значение равно наименьшему из виденных вами, добавьте его в список позиций; и
  • если это значение меньше самого маленького, которое вы видели, откажитесь от своего списка всех самых маленьких элементов (на самом деле они не были самыми маленькими) и сбросьте его до списка только текущей позиции.

Это также занимает время O(n), но делает это за один проход.