从列表中返回唯一的数字集

时间:2013-12-21 17:55:16

标签: algorithm

给定两个数字m和n,m小于n,返回一组从1到n的m个随机唯一数。例如,如果您有m = 6且n = 49,这与给出随机抽奖号码相同。

这样做的一种方法是使用随机数生成器获取0到1之间的数字,乘以n,截断为整数,检查数字是否已经设置,如果没有添加到set,重复直到我们有m个数字

另一种方法是首先创建一个数字为1到n的数组,随机重新排序数字,读取前m个数字。

我认为如果m与n相比较小,则第一个更好,例如,如果m = 1且n = 1000000,则第一个显然要快得多。但是如果m很大,我认为第二种方法会更好,例如,如果m = 500000和n = 1000000,如果你继续获得已经添加到的数字,那么第一种方法可能需要重复很多次。集。

我的问题是,是否有一种数学方法可以计算m和n之间的关系,以便何时使用一种方法比另一种方法更有效?

3 个答案:

答案 0 :(得分:1)

如果你从数组[1,2,...,n]开始,你可以重复地将第i个元素与从i到n随机选择的位置中的元素交换。为1< = i< = m执行此操作,您就完成了。

如果m<<< ñ。通过制作从整数到整数的映射,可以在不使用数组的情况下复制此行为。按上述步骤操作,但不是从数组的第i个位置读取,而是检查我是否是地图的键,然后拉出存储的值。类似地,您将元素放入第i个位置,而是将其作为与键i关联的值存储在地图中。

这是O(m)。

答案 1 :(得分:1)

我们通过它time complexity来衡量算法,它表示时间成本随着输入大小的增加而增加的速度。

在您的情况下,您的第一个算法无法正常工作。生成一个随机数,直到它不等于给定数字,有机会花费无限时间。所以让我们通过以下方式改进它:

  1. 列出所有N个候选人编号;
  2. 从1和N生成随机数R;
  3. 从列表中选择第R个数字;
  4. 从列表中删除所选的号码;设N为N-1;
  5. 转到第2步,直到获得M个选定的数字。
  6. 这种改进的算法具有时间复杂度的上限。无论使用线性列表还是链表,步骤3~4的复杂度为O(M)。他们将重复M次。此算法的总体复杂性为 O(NM)

    使用Fisher–Yates shuffle,第二种算法的复杂性为 O(N)

    所以,第二种算法是复杂性的赢家。请注意,这只意味着当输入大小增加时,获胜者的时间成本会增加 。它并不意味着总是比另一个花费更少的时间我们不会根据其绝对时间成本衡量算法,因为它因硬件,系统,语言和编译器等不同而不同。我们需要时间复杂度。 < / p>

答案 2 :(得分:1)

扩展我的评论。在我们选择一个尚未在集合中的元素之前,让E [X_i]成为预期的绘制数量。如果选择不在集合中的内容的概率是p,那么我们有

E[X_i] = 1/p

要看到这一点,请认为我们选择正确(概率为p),或者我们没有在这种情况下添加平局,因此

E[X_i] = p + (1 - p) * (1 + E[X_i])

E[X_i] = 1/p

现在对于第i个元素(从0开始),p = (n - i) / n,因此E[X_i] = n / (n - i)。使用E[X_i]对所有i < m进行求和,得到预期的抽取次数,以提取m个数字。对于m <= n/2,这明显优于创建n元素列表并对其进行混洗。