「这是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战」
说明:文章部分内容及图片出自网络,如有侵权请与我本人联系(主页有公众号:小攻城狮学前端)
作者:小只前端攻城狮、 主页:小只前端攻城狮的主页、 来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
题意描述
给你一个整数数组 nums ,设计算法来打乱一个没有重复元素的数组。
实现 Solution class:
- Solution(int[] nums) 使用整数数组 nums 初始化对象
- int[] reset() 重设数组到它的初始状态并返回
- int[] shuffle() 返回数组随机打乱后的结果
示例:
输入 ["Solution", "shuffle", "reset", "shuffle"] [[[1, 2, 3]], [], [], []] 输出 [null, [3, 1, 2], [1, 2, 3], [1, 3, 2]]
解释 Solution solution = new Solution([1, 2, 3]); solution.shuffle(); 打乱数组 [1,2,3] 并返回结果。任何 [1,2,3]的排列返回的概率应该相同。例如,返回 [3, 1, 2] solution.reset(); 重设数组到它的初始状态 [1, 2, 3] 。返回 [1, 2, 3] solution.shuffle(); 随机返回数组 [1, 2, 3] 打乱后的结果。例如,返回 [1, 3, 2]
提示:
- 1 <= nums.length <= 200
- -106 <= nums[i] <= 106
- nums 中的所有元素都是 唯一的
- 最多可以调用 5 * 10^4 次 reset 和 shuffle
分析
很明显题目就是一个考察我们经典的洗牌算法,思路是在前n-1张牌洗好的情况下,第n张牌随机与前n-1张牌的其中一张牌交换,或者不换,即是随机洗牌。
什么是洗牌?
- 我们得保证每一个元素在任意一个位置上的概率是一样的
- 最简单的想法,每次都选取一个放在第一个位置上--总共n轮
解法1:朴素版本
let n = this.nums.length;
let ans = new Array(n).fill(0);
let list = [];
this.ori.forEach(v=>list.push(v));
const floor = Math.floor
for(let i=0;i<n;i++) {
let id = floor(Math.random()*list.length);
ans[i] = list.splice(id,1);
}
return ans;
解法二:洗牌算法
let n = this.ori.length;
let ans = this.ori.slice();
const floor = Math.floor;
for(let i=0;i<n;i++) {
let k = floor(Math.random() * (n-i)) + i;
[ans[i],ans[k]] = [ans[k],ans[i]];
}
return ans;
最后:其实我们可以因为替换与不替换只有两种选择,概率都是50%,而随机数小于0.5 和 大于等于0.5 的概率 分别是 50%,因此可以根据随机数的大小,判断是否需要替换,通过对每一对索引值进行随机判断,从而达到随机打乱数组的目的、
感谢阅读,希望能对你有所帮助,文章若有错误或者侵权,可以在评论区留言或在我的主页添加公众号联系我。
写作不易,如果觉得不错,可以「点赞」+「评论」 谢谢支持❤