Выборка из резервуара — это семейство рандомизированных алгоритмов для случайного выбора k выборок из списка из n элементов, где n — либо очень большое, либо неизвестное число. Обычно n достаточно велико, чтобы список не помещался в основную память. Например, список поисковых запросов в Google и Facebook.
Итак, нам дан большой массив (или поток) чисел (для упрощения), и нам нужно написать эффективную функцию для случайного выбора k чисел, где 1 <= k <= n . Пусть входной массив будет stream [].
Простое решение — создать массив резервуара [] максимального размера k . Один за другим случайным образом выбирают элемент из потока [0..n-1] . Если выбранный элемент ранее не был выбран, поместите его в резервуар [] . Чтобы проверить, выбран ли предмет ранее или нет, нам нужно найти предмет в резервуаре [] . Временная сложность этого алгоритма будет O (k ^ 2) . Это может быть дорогостоящим, если k большое. Кроме того, это неэффективно, если ввод осуществляется в форме потока.
Это может быть решено за O (n) время . Решение также хорошо подходит для ввода в виде потока. Идея похожа на этот пост. Ниже приведены шаги.
1) Создайте массив резервуаров [0..k-1] и скопируйте в него первые k элементов потока [] .
2) Теперь один за другим рассмотрим все элементы от (k + 1) -го до n- го.
… А ) Генерация случайного числа от 0 до i, где i — индекс текущего элемента в потоке [] . Пусть сгенерированное случайное число равно j .
… Б) Если j находится в диапазоне от 0 до k-1 , заменить резервуар [j] на arr [i]
Ниже приведена реализация вышеуказанного алгоритма.
|
С
|
Джава
|
python3
|
C #
|
PHP
|
Выход:
Following are k randomly selected items 6 2 11 8 12 Note: Output will differ every time as it selects and prints random elements
Сложность времени: O (n)
Как это работает?
Чтобы доказать, что это решение работает идеально, мы должны доказать, что вероятность того, что любой элемент потока [i], где 0 <= i <n будет в конечном резервуаре [], равна k / n . Разделим доказательство на два случая, так как первые k элементов обрабатываются по-разному.
Случай 1: для последних элементов потока nk , т. Е. Для потока [i], где k <= i <n
Для каждого такого элемента потока stream [i] мы выбираем случайный индекс от 0 до i, и если выбранный индекс является одним из первых k индексов, мы заменяем элемент с выбранным индексом на stream [i]
Чтобы упростить доказательство, давайте сначала рассмотрим последний пункт . Вероятность того, что последний элемент находится в конечном резервуаре = Вероятность того, что один из первых k индексов выбран для последнего элемента = k / n (вероятность выбора одного из k элементов из списка размера n )
Давайте теперь рассмотрим второй последний пункт . Вероятность того, что второй последний элемент находится в конечном резервуаре [] = [Вероятность того, что один из первых k индексов будет выбран в итерации для потока [n-2] ] X [Вероятность того, что индекс выбран в итерации для потока [n-1 ] не совпадает с индексом, выбранным для потока [n-2] ] = [ k / (n-1)] * [(n-1) / n ] = k / n .
Точно так же мы можем рассмотреть другие элементы для всех элементов потока от stream [n-1] до stream [k] и обобщить доказательство.
Случай 2: для первых k элементов потока, т. Е. Для потока [i], где 0 <= i <k
Первые k элементов первоначально копируются в резервуар [] и могут быть удалены позже в итерациях для потока [k] в поток [n] .
Вероятность того, что элемент из потока [0..k-1] находится в конечном массиве = вероятность того, что элемент не выбран, когда элементы stream [k], stream [k + 1],…. поток [n-1] считается = [k / (k + 1)] x [(k + 1) / (k + 2)] x [(k + 2) / (k + 3)] x… x [ (n-1) / n] = k / n
Ссылки:
http://en.wikipedia.org/wiki/Reservoir_sampling
Пожалуйста, пишите комментарии, если вы обнаружите что-то неправильное или вы хотите поделиться дополнительной информацией по обсуждаемой выше теме.
Рекомендуемые посты:
- Количество подстрок в данной двоичной строке, делимое на 2
- Удовлетворить параболу, когда точка (A, B) и уравнение задано
- Наименьшее число, делящее минимальное количество элементов в массиве | Набор 2
- Наименьшая ненулевая подстрока, которая имеет любую перестановку, кратную 2 ^ K
- Наименьшее число, делящее минимальное количество элементов в массиве
- Ожидаемое количество ходов, чтобы достичь конца доски | Матрица возведения в степень
- Ожидаемое количество ходов, чтобы достичь конца доски | Динамическое программирование
- Удалите минимальные числа из массива, чтобы получить минимальное значение ИЛИ
- Удалите два последовательных целых числа от 1 до N, чтобы сделать сумму равной S
- Найдите два составных числа так, чтобы разница была N
- Найдите максимальный угол, под которым мы можем наклонить бутылку, не проливая воды
- Найти целочисленные точки (x, y) с манхэттенским расстоянием по крайней мере N
- Удалите один элемент, чтобы получить максимальное значение XOR
- Наибольшее число, делящее максимальное количество элементов в массиве
0.00 (0%) 0 votes