从具有加权概率的列表中随机选择

时间:2013-06-22 12:11:00

标签: algorithm random language-agnostic letter alphabet

我有一个N个元素的数组(表示给定字母表的N个字母),并且数组的每个单元格都包含一个整数值,该整数值表示该字母的给定文本中出现的次数。现在我想根据给定约束条件下的出现次数,随机选择字母表中所有字母的字母:

  • 如果字母具有正(非零)值,则可以随时由算法选择(当然,概率更大或更小)。

  • 如果字母A的值高于字母B,则算法必须更有可能选择它。

现在,考虑到这一点,我想出了一个可以完成这项工作的简单算法,但我只是想知道是否有更好的事情要做。这似乎是非常基础的,我认为可能有更聪明的事情要做,以便更有效地实现这一目标。这是我认为的算法:

  • 添加阵列中的所有频率。将其存储在SUM
  • 选择从0到SUM的随机值。将其存储在RAN
  • [while] RAN> 0,从第一个开始,访问数组中的每个单元格(按顺序),并从RAN中减去该单元格的值
  • 最后访问过的单元格是选定的单元格

那么,还有比这更好的事吗?我错过了什么吗?

我知道大多数现代计算机可以如此快速地计算这一点我甚至不会注意到我的算法是否效率低,所以这更像是一个理论问题而不是实际问题。

我更喜欢解释的算法,而不仅仅是答案的代码,但如果您更愿意在代码中提供答案,我对此没有任何问题。

2 个答案:

答案 0 :(得分:14)

想法:

  • 遍历所有元素,并将每个元素的值设置为到目前为止的累积频率。
  • 生成1到所有频率之和的随机数
  • 对此数字的值执行binary search(查找大于或等于该数字的第一个值)。

示例:

Element    A B C D
Frequency  1 4 3 2
Cumulative 1 5 8 10

生成1-10范围内的随机数(1 + 4 + 3 + 2 = 10,与累积列表中的最后一个值相同),进行二分查找,返回如下值:

Number   Element returned
1        A
2        B
3        B
4        B
5        B
6        C
7        C
8        C
9        D
10       D

答案 1 :(得分:8)

Alias Method已生成每个值的O(1)时间,但每次查询需要两个制服。基本上,您创建一个表,其中每列包含要生成的值之一,第二个值称为别名,以及在值及其别名之间进行选择的条件概率。使用您的第一件制服来挑选具有相同可能性的任何一列。然后根据您的第二个制服在主要值和别名之间进行选择。初始为n个值设置有效表需要O(n log n)工作,但是在表的构建生成值是恒定时间之后。您可以下载this Ruby gem以查看实际实施情况。

Marsaglia等人的另外两种非常快速的方法。描述here。他们提供了C implementations