gpt4 book ai didi

algorithm - 生成唯一(非重复)随机数的高效算法

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:13:05 25 4
gpt4 key购买 nike

我想解决以下问题。我必须在一个非常大的集合中进行采样,数量级为 10^20,并在不重复大小约为 10%-20% 的情况下提取样本。鉴于集合的大小,我认为像 Fisher–Yates 这样的算法是不可行的。

我在想像随机路径树这样的东西可能会在 O(n log n) 中完成它并且不能更快地完成,但我想问一下是否已经实现了这样的东西。

感谢您的宝贵时间!

最佳答案

我不知道我在下面描述的技术在随机性的正式测试中的表现如何,但它确实给出了“看似随机”的结果。

您可以使用 multiplicative inverse 来做到这一点.这个想法是您使用数学函数将 1-N 范围内的每个整数映射到同一范围内的唯一整数。这通常用于生成混淆 key ,但您可以通过更改种子值和从中提取项目的范围来调整它以生成随机子集。

不久前我写了一个blog entry关于如何生成混淆的顺序 key 。这是代码:

private void DoIt()
{
const long m = 101; // Number of keys + 1
const long x = 387420489; // must be coprime to m

// Compute the multiplicative inverse
var multInv = MultiplicativeInverse(x, m);

// HashSet is used to hold the obfuscated value so we can ensure that no duplicates occur.
var nums = new HashSet<long>();

// Obfuscate each number from 1 to 100.
// Show that the process can be reversed.
// Show that no duplicates are generated.
for (long i = 1; i <= 100; ++i)
{
var obfuscated = i * x % m;
var original = obfuscated * multInv % m;
Console.WriteLine("{0} => {1} => {2}", i, obfuscated, original);
if (!nums.Add(obfuscated))
{
Console.WriteLine("Duplicate");
}
}
}

private long MultiplicativeInverse(long x, long modulus)
{
return ExtendedEuclideanDivision(x, modulus).Item1 % modulus;
}

private static Tuple<long, long> ExtendedEuclideanDivision(long a, long b)
{
if (a < 0)
{
var result = ExtendedEuclideanDivision(-a, b);
return Tuple.Create(-result.Item1, result.Item2);
}
if (b < 0)
{
var result = ExtendedEuclideanDivision(a, -b);
return Tuple.Create(result.Item1, -result.Item2);
}
if (b == 0)
{
return Tuple.Create(1L, 0L);
}
var q = a / b;
var r = a % b;
var rslt = ExtendedEuclideanDivision(b, r);
var s = rslt.Item1;
var t = rslt.Item2;
return Tuple.Create(t, s - q * t);
}

该程序的前几行输出是:

1 => 43 => 1
2 => 86 => 2
3 => 28 => 3
4 => 71 => 4
5 => 13 => 5
6 => 56 => 6
7 => 99 => 7
8 => 41 => 8
9 => 84 => 9
10 => 26 => 10

如果您要更改函数开头的 mx 值以反射(reflect)您的数字范围,这将适用于您。而不是总是从 1 开始并捕获前 10% 或 20%,你可以从 50% 的标记开始,然后从那里开始。或者使用某种技术来获取每五个数字或其他任何数字,只要您的方法不会两次访问相同的数字即可。

如果您需要更多运行,只需更改 x 值即可。

生成乘法逆(将其视为随机数生成器的种子)是一个复杂度为 O(log n) 的操作。之后,生成每个数字的时间复杂度为 O(1)。

当然,如果您处理的是 10^20 范围内的数字,则必须修改代码以处理大整数类。

关于algorithm - 生成唯一(非重复)随机数的高效算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50669763/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com