给定一个数字流,请从该流中生成一个随机数。您只能使用O(1)空间,并且输入采用流的形式,因此不能存储以前看到的数字。
那么我们如何从整个流中生成一个随机数,以使选择任何数字的概率为1 / n。有O(1)多余的空间?这个问题是储层采样的一种变化。此处k的值为1。
1)将“ count”初始化为0,“ count”用于存储到目前为止在流中看到的数字计数。
2)对于流中的每个数字“ x”,请执行以下操作
….. a)将“计数”加1。
….. b)如果count为1,则将结果设置为x,然后返回结果。
….. c)生成一个从0到’count-1’的随机数。令生成的随机数为i。
….. d)如果i等于“ count – 1”,则将结果更新为x。
C++
// An efficient C++ program to randomly select
// a number from stream of numbers.
#include
#include
using namespace std;
// A function to randomly select a item
// from stream[0], stream[1], .. stream[i-1]
int selectRandom(int x)
{
static int res; // The resultant random number
static int count = 0; // Count of numbers visited
// so far in stream
count++; // increment count of numbers seen so far
// If this is the first element from stream,
// return it
if (count == 1)
res = x;
else
{
// Generate a random number from 0 to count - 1
int i = rand() % count;
// Replace the prev random number with
// new number with 1/count probability
if (i == count - 1)
res = x;
}
return res;
}
// Driver Code
int main()
{
int stream[] = {1, 2, 3, 4};
int n = sizeof(stream) / sizeof(stream[0]);
// Use a different seed value for every run.
srand(time(NULL));
for (int i = 0; i < n; ++i)
cout << "Random number from first " << i + 1
<< " numbers is " << selectRandom(stream[i]) << endl;
return 0;
}
// This is code is contributed by rathbhupendra
C
// An efficient C program to randomly select a number from stream of numbers.
#include
#include
#include
// A function to randomly select a item from stream[0], stream[1], .. stream[i-1]
int selectRandom(int x)
{
static int res; // The resultant random number
static int count = 0; //Count of numbers visited so far in stream
count++; // increment count of numbers seen so far
// If this is the first element from stream, return it
if (count == 1)
res = x;
else
{
// Generate a random number from 0 to count - 1
int i = rand() % count;
// Replace the prev random number with new number with 1/count probability
if (i == count - 1)
res = x;
}
return res;
}
// Driver program to test above function.
int main()
{
int stream[] = {1, 2, 3, 4};
int n = sizeof(stream)/sizeof(stream[0]);
// Use a different seed value for every run.
srand(time(NULL));
for (int i = 0; i < n; ++i)
printf("Random number from first %d numbers is %d \n",
i+1, selectRandom(stream[i]));
return 0;
}
Java
//An efficient Java program to randomly select a number from stream of numbers.
import java.util.Random;
public class GFG
{
static int res = 0; // The resultant random number
static int count = 0; //Count of numbers visited so far in stream
//A method to randomly select a item from stream[0], stream[1], .. stream[i-1]
static int selectRandom(int x)
{
count++; // increment count of numbers seen so far
// If this is the first element from stream, return it
if (count == 1)
res = x;
else
{
// Generate a random number from 0 to count - 1
Random r = new Random();
int i = r.nextInt(count);
// Replace the prev random number with new number with 1/count probability
if(i == count - 1)
res = x;
}
return res;
}
// Driver program to test above function.
public static void main(String[] args)
{
int stream[] = {1, 2, 3, 4};
int n = stream.length;
for(int i = 0; i < n; i++)
System.out.println("Random number from first " + (i+1) +
" numbers is " + selectRandom(stream[i]));
}
}
//This code is contributed by Sumit Ghosh
Python3
# An efficient python3 program
# to randomly select a number
# from stream of numbers.
import random
# A function to randomly select a item
# from stream[0], stream[1], .. stream[i-1]
def selectRandom(x):
# The resultant random number
res = 0;
# Count of numbers visited
# so far in stream
count = 0;
# increment count of numbers
# seen so far
count += 1;
# If this is the first element
# from stream, return it
if (count == 1):
res = x;
else:
# Generate a random number
# from 0 to count - 1
i = random.randrange(count);
# Replace the prev random number
# with new number with 1/count
# probability
if (i == count - 1):
res = x;
return res;
# Driver Code
stream = [1, 2, 3, 4];
n = len(stream);
# Use a different seed value
# for every run.
for i in range (n):
print("Random number from first",
(i + 1), "numbers is",
selectRandom(stream[i]));
# This code is contributed by mits
C#
// An efficient C# program to randomly
// select a number from stream of numbers.
using System;
class GFG
{
// The resultant random number
static int res = 0;
// Count of numbers visited
// so far in stream
static int count = 0;
// A method to randomly select
// a item from stream[0],
// stream[1], .. stream[i-1]
static int selectRandom(int x)
{
// increment count of
// numbers seen so far
count++;
// If this is the first
// element from stream,
// return it
if (count == 1)
res = x;
else
{
// Generate a random number
// from 0 to count - 1
Random r = new Random();
int i = r.Next(count);
// Replace the prev random
// number with new number
// with 1/count probability
if(i == count - 1)
res = x;
}
return res;
}
// Driver Code
public static void Main()
{
int[] stream = {1, 2, 3, 4};
int n = stream.Length;
for(int i = 0; i < n; i++)
Console.WriteLine("Random number from " +
"first {0} numbers is {1}" ,
i + 1, selectRandom(stream[i]));
}
}
// This code is contributed by mits
PHP
输出:
Random number from first 1 numbers is 1
Random number from first 2 numbers is 1
Random number from first 3 numbers is 3
Random number from first 4 numbers is 4
辅助空间: O(1)
这是如何运作的
我们需要证明以1 / n的概率选择了每个元素,其中n是到目前为止看到的项数。对于每个新的流项x,我们从0到’count -1’中选择一个随机数,如果选择的数字为’count-1’,则将先前的结果替换为x。
为了简化证明,让我们首先考虑最后一个元素,最后一个元素以1 / n的概率替换先前存储的结果。因此,获得最后一个元素作为结果的概率为1 / n。
现在让我们谈谈倒数第二个元素。当倒数第二个元素第一次处理时,它替换先前结果的概率为1 /(n-1)。当考虑第n个项目时,前一个结果保留的概率为(n-1)/ n。因此,在最后一次迭代中选择倒数第二个元素的概率为[1 /(n-1)] * [(n-1)/ n],即1 / n。
同样,我们可以证明倒数第三要素和其他要素。
参考:
储层采样