前端经久不衰的面试题--数组乱序

427 阅读2分钟

题目描述

给定一个未排序的数组,从中取出指定个数的随机元素,并以数组的形式进行返回,这道题目经常出现在前端各大厂的面试官手中,因此值得我们进行探讨和学习。

  • 测试实例

给定数组[1, 3, 5, 6, 8, 9, 5],要求输出一个随机数组,数组的个数是3,输出可以是[1,3,5]、[6,8,9].....等只要是随机的三个数字,并且取自给定数组即可。

实现思路

这道题目主要是考查我们对数组乱序算法的了解,直接使用random函数是肯定不行的,因为计算机内部的random函数并不是真正的随机函数,因此,我们可以考虑使用经典算法Fisher-Yates Shuffle算法。

  1. 从数组中随机选一个为混排的元素。
  2. 将第一步的元素与序列p的最后一个元素进行交换。
  3. 指向最后一个元素的指针前移并继续重复前两步。

实现代码

// 手撕数组乱序
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) + '%')));

image.png