在上周三早上面试的时候,一道题目是将 let arr = [1,2,3,4,5] 的数组处理成乱序,当时没有写出来,想着应该短期内不会遇到这题,就木有将这道题复盘,可巧合的是,周五早上的面试,又是同样的题目,呃呃呃,嘤嘤嘤......
目前找到了两种思路,这两种思路都需要一个在区间 [0, arr.length] 的区间中取一个随机值,辅助函数代码如下:
function getRandom(min, max) {
let random = Math.floor(Math.random() * (max - min + 1) + min)
return random
}
1.换牌
假设数组长度为 n = arr.length,将数字当成是牌
- 先将第1张牌和第1张牌更换,即,位置不变
- 再将第2张牌和前2张牌中的任意1张更换
- 再将第k张牌和前k张牌中的任意1张更换
- 将第n-1张牌和前n-l张牌中的任意1张更换
- 将第n张牌和任意1张牌更换
for (let i = 0; i < arr.length; i++) {
let j = getRandom(0, i);
let t = arr[i]
arr[i] = arr[j]
arr[j] = t
}
换牌的另一种方式是,将第1张和任意1张进行更换,将第2张和任意1张进行更换,依次类推,将最后一张牌和任意1张进行更换
for (let i = 0; i < arr.length; i++) {
let t = arr[i]
let j = getRandom(0, arr.length);
arr[i] = arr[j]
arr[j] = t
}
2.抽牌
假设数组长度为 n = arr.length,将数字当成是牌
- 先随机在n张牌中抽取1张放到新的牌堆上
- 在剩余的n-1张牌中抽取1张放到新的牌堆上
- 在剩余的k张牌中抽取1张放到新的牌堆上
- 在剩余的2张牌中抽取1张放到新的牌堆上
- 将最后1张牌放到新的牌堆上
let newArr = []
let len = arr.length
for (let i = 0; i < len; i++) {
let index = getRandom(0, arr.length - 1);
newArr.push(arr[index])
arr.splice(index, 1)
}
抽牌的另一种方式是,不需要开辟新的牌堆,直接将抽到的牌依次放到牌底即可,在真实代码中,可减少新数组的创建,减少空间复杂度
for (let i = 0; i < arr.length; i++) {
let index = getRandom(0, len - 1);
let buff = arr.splice(index, 1)
arr.push(...buff)
len--
}
以上是分别使用换牌和抽牌的方式进行的分析。
声明:换牌思路参考黄轶老师《全网稀缺Vue 2.0高级实战 独立开发专属音乐WebAPP》播放器随机模式的算法
链接为:coding.imooc.com/class/107.h…