我有一个生成随机数数组的函数。它可以工作,但是我认为对大数字它可能工作缓慢。有没有一种方法可以对其进行优化?
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;
}
答案 0 :(得分:2)
您的代码的问题在于,复杂度会以几何方式增长,因为它有机会生成已经被多次选择的数字。
我们需要实现的是在每次迭代中获取数字,以使迭代次数等于package.json
。
如何避免使用多个相同的随机数?
假设您要从 0-10 范围内的 5 个随机数
第一次迭代
使用值randomNumbersCount
生成随机数,例如var candidates = [0,1...10]
在结果中存储数字0
从candidates[0]
中删除0
。为了对candidates
数组进行有效索引,我们将candidates
放入candidates[candidates.length - 1]
并删除candidates[0]
,然后将执行此操作candidates[candidates.length - 1]
次。
第二次迭代
我们的候选数组现在为randomNumbersCount
生成随机数,再说一次[10,1,2,3,4,5,6,7,8,9]
。哇,我们生成了相似的随机数,但是那又如何呢?
我们的结果中包含0
,但是0
不再是candidates[0]
0
现在是candidates[0]
,因此我们选择10
的{{1}}并将其存储并将其从候选者中删除。将candidates[0]
(10
)放入candidates[candidates.length - 1]
并删除9
我们的结果现在是[0,10]
第三次迭代
我们的candidates[0]
现在为candidates[candidates.length - 1]
生成随机数,例如candidates
我们不再担心,因为我们知道[9,1,2,3,4,5,6,7,8]
是0
添加candidates[0]
(女巫是9
),我们正在保存结果,并将其从candidates[0]
我们的结果是9
,candidates
是[0,10,9]
以此类推
BTW的实现比解释要短得多:
candidates
答案 1 :(得分:2)
编辑-对于以后的任何用户,@ ScottSauyet的解决方案都应该是公认的答案。比我的解决方案更有效。
我认为解决此问题的算法最有效的方法是从0-maxNumber
生成所有可能数字的列表,对数组(O(n)
进行混洗,然后取第一个{{1} }改组数组中的数字。看起来如下:
randomNumbersCount
答案 2 :(得分:1)
通过mhodges的解决方案是相当有效的,但是仅当所寻求的计数非常接近最大值时才有效。如果您的数量少得多,则可能会出现问题,因为解决方案是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上查看性能比较