【问题标题】:What is an efficient algorithm to calculate weighted sums?计算加权和的有效算法是什么?
【发布时间】:2019-06-24 15:51:52
【问题描述】:

我不确定这里的技术术语是什么,所以我可以搜索的术语将不胜感激。

假设一个角色有多个不同权重的决定。

Decision A: 1
Decision B: 3
Decision C: 5
Sum: 9

代码的作用是将它们加在一起,这样有 1/9 的几率做出决定 A,做出决定 B 的几率为 3/9,做出决定 C 的几率为 5/9。

有一些因素会从池中删除和添加某些决策。这些权重不是固定的(例如,对于更智能的字符,B 可能为 2,或者根据各自的权重分为 B1 和 B2)。

现在我正在做的只是一个线性搜索,如下所示(在 JavaScript 中):

let totalWeight = 0;
for (let i = array.length - 1; i >= 0; i--) {
    totalWeight += array[i].weight;
}

// this function rolls a random number from 1 to totalWeight
let r = roll(1, totalWeight); 
let search = 1;
for (let i = 0; i < array.length; i++) {
    let w = array[i].weight;
    if (r >= search && r < (search+w)){
        return array[i];
    }
    search += w;
}

但这似乎不是很有效。看起来这里可以有一个二进制搜索算法,但我似乎想不出一个。有什么想法吗?

【问题讨论】:

    标签: javascript algorithm binary-search


    【解决方案1】:

    如果权重在每一轮中都发生变化,并且不同轮之间既没有共性也没有不变量,我认为没有一种算法可以显着优于线性扫描。

    Here 是执行此任务的算法列表。

    【讨论】:

      【解决方案2】:

      在查看了您输入的代码后,我认为rejection sampling 的技术/算法是您正在寻找的。要使用拒绝采样获得相同的代码输出:

      var sample = []; 
      for (let i = array.length - 1; i >= 0; i--) {
          for(let j = array[i].weight-1;j>=0;j--) {
              sample.push(i);
          }
      }
      // this function rolls a random number from 0 to sample.length-1
      // which sample.length should be equivalent to your total weight 
      let r = roll(0, sample.length-1);
      return array[sample[r]];
      

      上面的代码降低了时间复杂度,但增加了空间复杂度。

      如果您尝试在没有rejection sampling 的情况下在算法中实现binary search,请尝试以下代码:

      let totalWeight = 0;
      //add one property into your array, call it accumulative_weight or aw
      
      for (let i = array.length - 1; i >= 0; i--) {
          totalWeight += array[i].weight;
          //assign the accumulative_weight property 
          array.aw = totalWeight;
      }
      
      // this function rolls a random number from 1 to totalWeight
      let r = roll(1, totalWeight); 
      let start = 0;
      let end = array.length;
      let position = "not found";
      while(start!=end)
      {
          let target = parseInt((end-start)/2);
          if( array[target].aw > r )
              end = target;
          else if ( array[target].aw - array[target].weight < r )
              start = target;
          else
          {
              let position = target;
              break; 
          }
      }
      return position;
      

      请注意,您的数组必须排序。希望能帮助到你。

      【讨论】:

      • 这个问题的主要问题是每个函数调用的权重都会改变。正常的采样算法要么需要 O(n) 设置时间和 O(1) / O(log n) 采样时间,反之亦然。如果预计算的数组不能(部分)在不同的调用之间重用,我认为任何其他采样算法都不会比简单的线性扫描好得多。
      猜你喜欢
      • 1970-01-01
      • 2020-01-21
      • 1970-01-01
      • 2011-01-26
      • 2012-08-12
      • 2021-01-05
      • 2011-07-13
      • 2012-08-14
      • 1970-01-01
      相关资源
      最近更新 更多