zoukankan      html  css  js  c++  java
  • 单次遍历,带权随机选取问题

    在以前的链表单次遍历,随机选取问题中,我们采用水塘抽象方法解决了问题。问题结点带权呢?

    问题描述:有一组数量未知的数据,每个元素有非负权重。要求只遍历一次,随机选取其中的一个元素,任何一个元素被选到的概率与其权重成正比。

    设元素总数为n,当然在遍历结束前n是未知的。设第i(1 <= i <= n)个元素的权重为wi(> 0),则权重总和为w=sum_{i=1}^{n}{w_i},也是在遍历结束时才知道的。根据题目要求,第i个元素被选取的概率应该等于p_i=frac{w_i}{w}

    虽然加了个权重,但解法依旧非常简单,在单次遍历,等概率随机选取问题中的RandomSelect函数上稍作修改就得到本问题的解法,依旧是O(n)时间,O(1)辅助空间:

    from random import Random
    
    def WeightedRandomSelect(rand=None):
      selection = None
      totalweight = 0.0
      if rand is None:
        rand = Random()
      while True:
        # Outputs the current selection and gets next item
        (item, weight) = yield selection
        totalweight += weight
        if rand.random() * totalweight < weight:
          selection = item

    其中Python的random.random()返回[0, 1)之间的随机小数。

    把rand.random()<weight/totalWeigth,则会有好理解一点。(同等概率选取类似,random(1,i)等于1就替换.i分之一,只不过不同概率用权重占比来表示了。)

    算法很简单:对于任意的i(1 <= i <= n),按照如下方法给第i个元素分配一个键值key(其中ri是一个0到1之间等概率分布的随机数):

     

    之后,如果要随机选取一个元素,就去key最大的那个;如果要选取m个元素,就取key最大的m个。

    真不知道是怎么想出来的这样的方法,不过还是先来关注一下证明的过程。

    算法的核心,计算每个元素的随机权重,python版:

    key = rand.random() ** (1.0 / weight)
     
    选择key最大的m个,就是结果

    更多:

    http://www.gocalf.com/blog/weighted-random-selection.html

    http://www.gocalf.com/blog/weighted-random-selection-2.html

    http://www.cnblogs.com/SuperBrothers/archive/2012/11/13/2768788.html

  • 相关阅读:
    Qt之添加QLabel的点击事件
    Qt之布局管理--基本布局
    Qt之界面实现技巧
    Qt之键盘讲解
    Qt之多窗口切换
    Qt之自定义信号和槽函数
    Qt之重写QLabel类
    mysql学习(四)-字段类型
    mysql学习(三)
    mysql 复习与学习(二)数据库及表结构的创建删除
  • 原文地址:https://www.cnblogs.com/youxin/p/3353024.html
Copyright © 2011-2022 走看看