I tested the shuffling algorithm in the interview before, and the writing was relatively simple at the time. The core ideas are as follows:
- Create an empty result array;
- Randomly sample from the original array in turn, and then sequentially
push
to the result array; - To prevent collisions, delete the element from the original array after each sampling;
In fact, there is another way to get the elements from the original array in order, and then put them in a random position in the new array, but this cannot eliminate the collision problem.
function shuffle(arr) {
let len = arr.length;
let res = [];
for (let i=0; i<len; i++) {
res.push(sample(arr));
}
return res;
}
function sample(arr) {
// 数组随机取样
let randIndex = Math.floor(Math.random() * arr.length);
// 获取元素并从原数组中删除
let [ele] = arr.splice(randIndex, 1);
return ele;
}
You can see that there are two problems with the above code:
- Create a new array, resulting in the use of additional space;
- Deleting elements from the array requires moving the subscripts of other elements, resulting in a total time complexity of
O(n^2)
;
So is there a way to modify the original array without creating a new array? Today I saw a Fisher-Yates shuffling algorithm. The idea is similar to the above code, but instead of creating a new array, it uses an element exchange method similar to that of fast sorting:
- Traverse in reverse order starting from the last element of the array;
- Randomly extract elements from the array containing the current element and exchange with the current element;
- Keep traversing forward until all elements are exchanged;
function randomIndex(index: number): number {
return Math.floor(Math.random() * (index + 1));
}
function swap<T>(arr: T[], a: number, b: number) {
let temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
export function shuffle<T>(arr: T[]): T[] {
for (let i=arr.length-1; i>=0; i--) {
let r = randomIndex(i);
swap<T>(arr, r, i);
}
return arr;
}
const res = shuffle<number>([1, 2, 3, 4, 5, 6]);
console.log(res);
As can be seen from the code, each step is to randomly extract elements from the array and put them at the end of the array, then the pointer advances one bit, and continue to extract elements from the remaining array and put them at the end of the array. According to this process and so on, the elements of the entire array are eventually disrupted. The idea of implementation is actually the same as my previous code, but there are two improvements:
- No new array is created, and the space complexity is
O(n)
; - Through the method of element exchange, the problem of removing the elements from the array that causes the subscripts of other elements to be moved is
O(n)
, and the time complexity is 06167e39417a21;
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。