在JavaScript开发过程中,生成一组不重复的随机数并快速获取其中的最小值,是很多业务场景下的常见需求,比如抽奖系统的去重抽奖、数据采样中的唯一样本筛选等。不同的实现方案在性能上存在明显差异,选择高效的方法能显著提升代码运行效率。

基础实现方案:循环去重+排序取值
最直观的思路是先生成随机数,通过循环判断是否已经存在,去重后再排序取第一个值作为最小值。这种方式逻辑简单,适合数据量较小的场景。
// 生成指定范围、指定数量的唯一随机数,返回最小值
function getMinUniqueRandom_basic(minRange, maxRange, count) {
// 边界校验
if (maxRange - minRange + 1 < count) {
throw new Error('范围不足以生成指定数量的唯一随机数');
}
const uniqueSet = new Set();
while (uniqueSet.size < count) {
// 生成[minRange, maxRange]区间的随机整数
const randomNum = Math.floor(Math.random() * (maxRange - minRange + 1)) + minRange;
uniqueSet.add(randomNum);
}
// 将Set转为数组排序,取第一个元素
const sortedArr = Array.from(uniqueSet).sort((a, b) => a - b);
return sortedArr[0];
}
// 示例调用:生成1-100之间的5个唯一随机数,获取最小值
const result1 = getMinUniqueRandom_basic(1, 100, 5);
console.log(result1);
优化方案:生成时记录最小值
上面的方案需要排序后取值,时间复杂度包含排序的O(n log n),可以在生成随机数的过程中直接记录最小值,省去排序步骤,将时间复杂度降到O(n)。
function getMinUniqueRandom_optimize(minRange, maxRange, count) {
if (maxRange - minRange + 1 < count) {
throw new Error('范围不足以生成指定数量的唯一随机数');
}
const uniqueSet = new Set();
let minValue = Infinity; // 初始化最小值为无穷大
while (uniqueSet.size < count) {
const randomNum = Math.floor(Math.random() * (maxRange - minRange + 1)) + minRange;
// 如果随机数不存在,添加到Set并更新最小值
if (!uniqueSet.has(randomNum)) {
uniqueSet.add(randomNum);
if (randomNum < minValue) {
minValue = randomNum;
}
}
}
return minValue;
}
// 示例调用
const result2 = getMinUniqueRandom_optimize(1, 100, 5);
console.log(result2);
大数量场景方案:预生成区间再随机选取
如果需要生成的随机数数量接近区间总数,或者区间本身不大,可以先生成整个区间的有序数组,再随机选取元素,效率会更高。
function getMinUniqueRandom_large(minRange, maxRange, count) {
if (maxRange - minRange + 1 < count) {
throw new Error('范围不足以生成指定数量的唯一随机数');
}
// 生成完整的区间有序数组
const rangeArr = [];
for (let i = minRange; i <= maxRange; i++) {
rangeArr.push(i);
}
// 随机打乱数组(Fisher-Yates洗牌算法)
for (let i = rangeArr.length - 1; i > 0; i--) {
const randomIndex = Math.floor(Math.random() * (i + 1));
[rangeArr[i], rangeArr[randomIndex]] = [rangeArr[randomIndex], rangeArr[i]];
}
// 截取前count个元素,第一个就是最小值(因为原数组有序,打乱后第一个元素即为随机选取的最小值)
const selectedArr = rangeArr.slice(0, count);
return selectedArr[0];
}
// 示例调用
const result3 = getMinUniqueRandom_large(1, 100, 5);
console.log(result3);
方案对比
我们可以通过一张表格对比不同方案的适用场景和性能特点:
| 方案名称 | 时间复杂度 | 适用场景 | 优点 |
|---|---|---|---|
| 基础循环去重+排序 | O(n log n) | 小数量随机生成 | 逻辑简单,易理解 |
| 生成时记录最小值 | O(n) | 中数量随机生成 | 无需排序,性能更优 |
| 预生成区间随机选取 | O(m)(m为区间长度) | 大数量或区间较小的场景 | 生成效率高,无重复判断开销 |
注意事项
- 生成随机数前一定要做边界校验,避免区间范围小于需要生成的数量导致死循环。
- 如果不需要整数随机数,只需要浮点型,可以调整生成随机数的逻辑,去掉
Math.floor即可,最小值记录逻辑不变。 - 洗牌算法在打乱大数组时性能会下降,如果区间长度超过10万,建议优先选择生成时记录最小值的方案。
JavaScript唯一随机数获取最小值高效方法修改时间:2026-06-25 15:51:33