Автор оригинала: Alex Williams.
Предположим, у вас есть массив с n элементами, и вы хотите случайное подмножество с элементами k. Какие стратегии могут вы думать о том, чтобы сделать это как можно эффективно?
Найти минутку.
Почему вы должны заботиться о эффективности? Это потому, что генераторы случайных чисел должны сделать компромисс между статистическими тестами, которые они могут пройти и их производительность.
Займет другой момент.
Подсказка: Вы можете перевести это в проблему генерации случайных чисел от 0 до N – 1 без дубликатов? Эти цифры могут служить индексами, которые вы используете для выбора членов массива.
Что теперь? Кажется ли ваше решение слишком много работы, когда k маленький? Или это невозможно, когда K находится рядом? Здесь это ссылка, где она обсуждается. Если ваше решение имеет одну из упомянутых проблем, не чувствуй себя плохой Джон Скелет Дали 3 решения, ни один из которых не эффективны в целом.
Одно интересное решение состоит в том, чтобы объединить свои первые и второе подходы, то есть продолжайте собирать случайные числа и помещать их в хеш-набор или бинарное дерево, когда k маленький и перемешивает массив [0, …, n – 1], когда k большой Отказ Но что значит маленький и большой?
Для длинной истории вы можете посмотреть Screencast где я получу ответ. КОРОТКАЯ ВЕРСИЯ Я могу задать вопрос «Насколько большой CAN C будет до ожидаемого количества случайных чисел, которые необходимо превышать n»? Причина, по которой актуален этот вопрос, так это то, что подход 2 всегда требует случайных чисел. Оказывается красивый ответ; K <(1 -.63212055882 * N Если и только если ожидаемое количество случайных чисел, требуется TL; DR Вот реализация в Python:from random import randrange
def shuffle(list):
n = len(list)
for i in range(n - 1):
j = randrange(i, n-1) # i <= j < n
value = list[i]
list[i] = list[j]
list[j] = value
def getDistinctRandomNumbers(inclusiveMin, exclusiveMax, amount):
result = set()
while len(result) != amount:
result.add(randrange(inclusiveMin, exclusiveMax))
return result
def getRandomElements(list, amount):
length = len(list)
amount = min(length, amount)
if amount < 0.63212055882 * length:
randomNumbers = getDistinctRandomNumbers(0, length, amount)
result = [None]*amount
i = 0
for num in randomNumbers:
result[i] = list[num]
i+=1
return result
else:
shuffle(list)
return list[0:amount]