Если вы выбираете M
элементов из N
, стратегия меняется в зависимости от того, имеет ли M
тот же порядок, что и N
, или намного меньше (то есть меньше примерно N / log N).
Если они похожи по размеру, вы просматриваете каждый элемент от 1
до N
. Вы отслеживаете, сколько элементов у вас есть на данный момент (назовем это m
элементов, выбранных из n
, через которые вы прошли), а затем вы берете следующее число с вероятностью (M-m)/(N-n)
и в противном случае отбрасываете его. Затем вы обновите m
и n
соответствующим образом и продолжите. Это алгоритм O(N)
с низкой постоянной стоимостью.
Если, с другой стороны, M
значительно меньше N
, тогда стратегия передискретизации является хорошей. Здесь вы захотите отсортировать M
, чтобы вы могли быстро их найти (и это будет стоить вам O(M log M)
времени - например, вставьте их в дерево). Теперь вы выбираете числа от 1
до N
и вставляете их в свой список. Если вы обнаружите столкновение, выберите еще раз. Вы будете сталкиваться примерно M/N
случаев (фактически, вы интегрируете от 1 / N до M / N), что потребует от вас выбора снова (рекурсивно), поэтому вы ожидаете, что для завершения процесса потребуется M/(1-M/N)
выборок. Таким образом, ваша стоимость этого алгоритма составляет примерно O(M*(N/(N-M))*log(M))
.
Это такие простые методы, что вы можете просто реализовать оба - при условии, что у вас есть доступ к отсортированному дереву - и выбрать тот, который подходит с учетом той доли чисел, которая будет выбрана.
(Обратите внимание, что выбор чисел является симметричным с отсутствием выбора, поэтому, если M
почти равно N
, вы можете использовать стратегию повторной выборки, но выберите те числа, которые не включать; это может быть победой, даже если вам нужно протолкнуть все почти N
числа, если генерация случайных чисел обходится дорого.)
person
Rex Kerr
schedule
16.09.2010