繁体   English   中英

随机数数组优化

[英]Array of random numbers optimization

我有一个生成随机数数组的函数。 它可以工作,但是我认为对大数字它可能工作缓慢。 有没有一种方法可以对其进行优化?

 function renerateRandomNumbers(maxNumber, randomNumbersCount) { let i; const arrResult = []; for (i = 0; i < randomNumbersCount; i++) { let rand = Math.random() * (maxNumber); rand = Math.round(rand); if (arrResult.indexOf(rand) === -1 ) { arrResult.push(rand); } else { i--; } } return arrResult; } 

您的代码的问题在于,复杂度会以几何方式增长,因为它有机会生成已经被多次选择的数字。

我们需要实现的是在每次迭代中获取数字,以使迭代计数等于randomNumbersCount

如何避免多个相同的随机数?

假设您要有0-10个范围内的5个随机数

第一次迭代

  1. 创建具有值var candidates = [0,1...10]的数组

  2. 产生随机数,假设为0

  3. 在结果中存储candidates[0]数字candidates[0]

  4. candidates删除0 为了对candidates数组进行有效的重新索引,我们将把candidates[candidates.length - 1]放入candidates[0]并删除candidates[candidates.length - 1]

  5. 然后将执行此操作randomNumbersCount次。

第二次迭代

  1. 我们的候选数组现在为[10,1,2,3,4,5,6,7,8,9]

  2. 生成随机数,再说一次0 哇,我们生成了相似的随机数,但是那又如何呢?

  3. 我们的结果中有0 ,但是candidates[0]不再是0 candidates[0]现在是10

  4. 因此我们挑选candidates[0]10 ,并且将其存储,并从候选中移除。 candidates[candidates.length - 1]9 )放入candidates[0]并删除candidates[candidates.length - 1]

  5. 我们的结果是[0,10]

第三次迭代

  1. 我们的candidates现在是[9,1,2,3,4,5,6,7,8]

  2. 产生随机数,假设为0

  3. 我们不再担心,因为我们知道candidates[0]9

  4. 添加candidates[0] (女巫为9 ),我们正在保存结果,并将其从candidates删除

  5. 我们的结果是[0,10,9]candidates[8,1,2,3,4,5,6,7]

等等

BTW的实现比解释要短得多:

 function renerateRandomNumbers(maxNumber, randomNumbersCount) { var candidates = [...Array(maxNumber).keys()]; return Array(randomNumbersCount).fill() .map(() => { const randomIndex = Math.floor(Math.random() * candidates.length) const n = candidates[randomIndex] candidates[randomIndex] = candidates[candidates.length - 1] candidates.length = candidates.length - 1 return n }) .sort((a, b) => a - b) // sort if needed } console.log (renerateRandomNumbers(10, 5)) 

编辑 -对于任何未来的用户,@ ScottSauyet的解决方案应该是公认的答案。 它是比我的解决方案更有效的解决方案。

我认为解决该问题的算法上最有效的方法是从0-maxNumber生成所有可能数字的列表,对数组( O(n) )进行混洗,然后从混randomNumbersCount的数组中获取第一个randomNumbersCount数字。 它看起来像下面的样子:

 function shuffleArray(array) { for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } } function generateRandomNumbers(maxNumber, randomNumbersCount) { var possibleNumbers = []; // populate array with all possible values for (var i = 0; i <= maxNumber; i++) { possibleNumbers.push(i); } // shuffle the array to get a random order of the possible numbers O(n) shuffleArray(possibleNumbers); // trim the array down to only the first n numbers where n = randomNumbersCount possibleNumbers.length = randomNumbersCount; return possibleNumbers; } console.log (generateRandomNumbers(10, 5)); console.log (generateRandomNumbers(10, 5)); console.log (generateRandomNumbers(10, 5)); 

方案的解决方案是相当有效的,但仅当所寻求的数量非常接近最大数量时才有效。 如果您的计数明显较小,则可能会出现问题,因为解决方案为O(m + n) ,其中m为最大值, n为所需计数。 在空间上也是O(m) 如果m大,这可能是个问题。

一个变体可以通过做相同的事情来使它在时间和空间上大约为O(n) ,但是当我们到达count项时,并且不预先填充数组而是默认为其索引,就可以停止随机播放。

 function venerateRandomNumbers(max, count) { // todo: error if count > max const arr = new Array(max + 1) for (let i = max; i > max - count; i--) { const j = Math.floor(Math.random() * (i + 1)) const temp = arr[j] || j arr[j] = arr[i] || i arr[i] = temp } return arr.slice(-count) } console.log(venerateRandomNumbers(1000000, 10)) 

您可以在repl.it上查看性能比较

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM