我有一个大小为N的数组,可能会以某种方式排序。我想在<中获取此数组中的Z个随机项。 O(N)时间。
我的理解是,如果我使用Underscore的_.shuffle()对我的数组进行洗牌,那将花费O(N)时间。所以,洗牌,然后抓住第一个Z项目。
如果我在N之间生成Z个随机数,我想我可以进入非常丑陋的最坏情况。这是因为如果N是105,Z就是100 ..好吧,会有很多重叠,也许我会重新滚动Z几百次。
我想知道这个问题是否有简单的解决方案?我没有看到任何特定于任务的Underscore方法。
答案 0 :(得分:2)
以下是一些需要考虑的算法:
:一种。混洗强>
总体复杂性:O(N)
function A(array, z) {
return _.first(_.shuffle(array), z);
}
<强> B中。通过重新滚动随机选择
整体复杂性:
对于Z&lt;&lt; N,O(Z)平均情况
对于Z = N,O(N ^ 2)平均情况
function B(array, z) {
var pickedIndices = {};
var result = [];
while (result.length < z) {
var randomIndex = Math.floor(Math.random() * array.length);
if (!(randomIndex in pickedIndices)) {
pickedIndices[randomIndex] = 1;
result.push(array[randomIndex]);
}
}
return result;
}
<强>℃。随机选择与删除
总体复杂性:O(Z * N)
function C(array, z) {
var result = [];
array = array.slice(0);
for (var i = 0; i < z; i++) {
var randomIndex = Math.floor(Math.random() * array.length);
result.push(array.splice(randomIndex, 1)[0]);
}
return result;
}
效果测试
http://jsperf.com/fetch-z-random-items-from-array-of-size-n
当N = 100且Z = 10时,算法C是最快的(可能是因为大多数逻辑使用本机函数和/或易于优化,对于N和Z的小值比算法复杂度更重要)。
当N = 100且Z = 100时,算法A是最快的。
当N = 1000且Z = 100时,算法B是最快的。
<强>结论强>
我考虑过的人中没有一个最好的算法;这取决于您的数据的特征。如果您的数据特征可能不同,则可能值得进一步测试并根据N和Z的值创建一些标准,以选择性地选择最佳算法。
例如,如果Z <= N / 2,则可以使用算法B;否则,算法A.
简而言之,没有“简单”的解决方案始终具有出色的性能。
答案 1 :(得分:1)
我不认为我完全理解你的问题,但是如果你想从阵列中获取一个随机元素并且不能重复它,那么你只能滚动的次数少于那里是元素,然后你可以试试这个
function shuffle(obj, rounds, deep) {
var length = obj.length;
if (length < 2) {
return;
}
var rounds32 = rounds >>> 0 || 1;
var deepBool = deep === true;
var roundCount = 0;
var index, rnd, tmp;
while (roundCount < rounds32) {
index = length;
while (index) {
if (Array.isArray(obj[index - 1])) {
shuffle(obj[i], rounds32, deepBool);
}
rnd = Math.floor(Math.random() * index);
index -= 1;
tmp = obj[index];
obj[index] = obj[rnd];
obj[rnd] = tmp;
}
roundCount += 1;
}
}
var array = [];
for (var count = 0; count < 100; count += 1) {
array.push(count);
}
shuffle(array);
var rolls = 10;
console.log(array.slice(0, rolls));
&#13;