题目描述
给定一个未排序的数组,从中取出指定个数的随机元素,并以数组的形式进行返回,这道题目经常出现在前端各大厂的面试官手中,因此值得我们进行探讨和学习。
- 测试实例
给定数组[1, 3, 5, 6, 8, 9, 5],要求输出一个随机数组,数组的个数是3,输出可以是[1,3,5]、[6,8,9].....等只要是随机的三个数字,并且取自给定数组即可。
实现思路
这道题目主要是考查我们对数组乱序算法的了解,直接使用random函数是肯定不行的,因为计算机内部的random函数并不是真正的随机函数,因此,我们可以考虑使用经典算法Fisher-Yates Shuffle算法。
- 从数组中随机选一个为混排的元素。
- 将第一步的元素与序列p的最后一个元素进行交换。
- 指向最后一个元素的指针前移并继续重复前两步。
实现代码
// 手撕数组乱序
function getRandomArr(arr,count) {
// 定义分割点
let point = arr.length - count;
// 数组的长度
let len = arr.length;
while (len > point) {
// 以len下标为基准:index表示的是len下标前面的任意一个元素下标
let index = Math.floor((len--) * Math.random())
// 如果index和len不同,则交换
if (index != len) {
let temp = arr[index];
arr[index] = arr[len];
arr[len] = temp;
}
}
return arr.slice(point);
}
console.log(getRandomArr([1, 3, 5, 6, 8, 9, 5], 3));
对数组乱序进行单元测试
主要是测试每一个值在不同下标出现的概率是否相等。
function shuffle(array) {
var j, x, i;
for (i = array.length; i; i--) {
j = Math.floor(Math.random() * i);
x = array[i - 1];
array[i - 1] = array[j];
array[j] = x;
}
return array;
}
var statistics = new Array(5).fill(0).map(() => new Array(5).fill(0));
for (let i = 0; i < 100000; i++) {
let arr = [1, 2, 3, 4, 5];
arr = shuffle(arr);
arr.forEach((value, index) => {
statistics[index][value - 1]++;
})
}
console.table(statistics.map(item => item.map(value => (value / 100000 * 100).toFixed(2) + '%')));