【问题标题】:Is there an algorithm for generating random pairs of a set of numbers?是否有生成一组数字的随机对的算法?
【发布时间】:2021-08-26 04:41:13
【问题描述】:

我有一个不连续的数字 N 列表(例如{ 1, 2, 3, 6, 8, 10}),我需要在 N 中逐步创建随机数字对并将它们存储在一个列表中,其中不能有两次相同的对。

例如,对于 3 个不同数字的列表,有 6 个可能的对(不包括相同的数字对):

{ 4, 8, 9 } 列表为例,可能的对是:

(4,8) (4,9) (8,4) (8,9) (9,4) (9,8)

例如,当我们到达 30 的数字列表大小时,我们会得到 870 个可能的配对,而使用我当前的方法,我的效率会越来越低,可能配对越多。

例如,现在我使用 30 大小的数字列表的策略是:

N = { 3, 8, 10, 15, 16, ... } // size = 30

// Lets say I have already a list with 200 different pairs
my_pairs = { (8,16), (23, 32), (16,10), ... }

// Get two random numbers in the list
rn1 = random(N)
rn2 = random(N)

Loop through my_pairs to see if the pair (rn1,rn2) has already been generated

If there is one, we pick two new numbers rn1 & rn2 at random and retry adding them to my_pairs

If not then we add it to the list

问题是我们在 my_pairs 中的配对越多,配对不在该列表中的可能性就越小。所以我们必须多次检查多个随机对,每次都遍历列表。

我可以尝试在开始时生成所有可能的对,每次我需要将随机对添加到列表中时,将列表打乱并弹出一个元素。 但是当我的数字列表大小增加时(例如 100 个不同数字的 9900 个可能对),存储所有可能的对将占用大量空间。 而且我在处理过程中在 N 中添加了数字,所以我不能每次都重新计算所有可能的对。

是否有生成随机唯一对的算法?

也许使用矩阵或将我的配对存储在某种树形图中会更快?

【问题讨论】:

  • 将生成的对存储在哈希表中,而不是线性列表中。
  • @AloisChristen 实际上我纠正了自己,我没有从 N 中删除数字,只是添加。没有最小值和最大值,它们必须> 0。我使用了所有可能配对的 ~10% 到 ~70% 之间,它变化很大。通常我从一个小的 N 开始,然后逐渐添加数字。 N 的大小有时可以达到 10k 以上。我提到了数学和图形标签,因为我可能正在考虑使用矩阵或树图数据结构。
  • @subski:哈希表的重点是“检查整个哈希表”的时间实际上并没有随着哈希表变大而增加。 (无论如何,平均而言)此外,如果您用尽了 2/3 的可能性,则平均需要 3 次尝试才能找到未使用的元素。根据您的评论,这大概是最坏的情况。在整个问题中,预计拒绝策略的速度比不检查 fir 重复的速度要慢两倍。
  • 全代对和哈希表似乎都很好。根据您需要优化的程度,您甚至可以选择混合解决方案(从哈希表开始,切换到固定 % 以外的所有对)如果您生成所有对,this structure 可能会有所帮助
  • 准确地说,如果你使用所有可能的对,当添加一个新元素时,你只需要使用添加的元素生成可能的对。由于您永远不会删除元素,因此现有的对在被选中之前一直有效。

标签: algorithm math graph combinations


【解决方案1】:

这在很大程度上取决于您要优化什么。

如果您想让事情变得简单且易于维护,拥有一个包含所有生成数字的哈希集听起来很合理。这里的假设是检查成员资格和添加新元素的平均时间应该是 O(1)。

如果您担心空间需求,因为您经常使用多达 70% 的可能配对,那么您可以针对空间进行优化。为此,我首先在每个可能的对和单个整数之间建立映射。我会以一种可以轻松将更多数字添加到 N 的方式这样做。

      +0     +1
 0  (0,1)  (1,0)
 2  (0,2)  (2,0)
 4  (1,2)  (2,1)
 6  (0,3)  (3,0)
 8  (1,3)  (3,1)
10  (2,3)  (3,2)

这样的事情会将一个整数 i 映射到一对 (a,b) 索引到你的序列 N 中,你然后可以在 N 中查找以将它们变成一对实际的元素。你可以想出这个映射的公式,虽然从 i(a,b) 的转换需要在某处求平方根。

当你有了这个,从一组任意数字中挑选一对的任务就变成了从一个连续的整数范围中挑选一个整数的任务。现在,您可以使用位图非常有效地存储每个索引,无论您过去是否已经选择了该索引。对于低百分比的选择对,位图可能比仅选择值的哈希图更消耗内存,但是当您接近 70% 的所有对被选择时,它会更有效。我希望一个典型的哈希映射条目至少消耗 3×64=192 位的存储空间,因此一旦选择了 1/192=0.52% 的所有值,位图就会开始节省内存。增加位图可能仍然很昂贵,因此估计 N 的最大大小可能有助于预先分配足够的内存。

如果您有一个昂贵的随机数生成器,或者担心整个事情的最坏情况时间复杂度,那么您可能希望避免可能导致已经选择对的多次尝试。为了实现这一点,您可能会将所有选择对的集合存储在某种搜索树中,其中每个节点还跟踪其子树包含的叶子数量。这样,您可以在与尚未选择的对的大小相对应的范围内生成一个随机数,然后使用该树中的信息将所有已选择的索引的数量添加到所选值中小于该值.我还没有计算出所有细节,但我相信这样可以将其转换为 O(log n) 最坏情况时间复杂度,而不是 O(1) 平均情况,但 O(n) 甚至 O( ∞) 我们之前遇到的最坏情况。

【讨论】:

  • 感谢您的指导,我创建了从单个整数生成对的函数,而我刚刚完成实现整个事情。我认为我的解决方案非常有效,可以很好地处理极端情况。我很快就会在这里发布完整的代码。
猜你喜欢
  • 2012-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-24
  • 1970-01-01
  • 2012-01-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多