快速理解洗牌算法

335 阅读1分钟

问题:一个数组里有a到z 26个字母,随机抽取字母,不能重复,保证每个字母被抽取到的概率一样。

生成随机数的方法大家都知道Math.random(),关键在于如何去除重复的数。

思路:每次从没有取过的字母中选择一个和最后一位进行对换。

直接结合代码理解:

let swap = arr => {
    let result = [];
    // 注意了length是从1开始的,所以要arr.length - 1
    for(let i = arr.length - 1; i > 0;) {
        let index = Math.floor(Math.random()*i) 
        result.push(arr[index]);
        arr[index] = arr[i--];
    }
    return result
}

第一次循环的时候:

假设index摇到了24,也就是字母y。然后y和最后一位z交换,i - 1

[a,b,c...x, y ,z] -> [a,b,c...x,z, y ]

第二次循环的时候:

此时的i=24,数组中能取到的字母变成了

[a,b,c...x,z] ,y 这个已经抽到过的字母被完美的排除在外