【算法-LeetCode】384. 打乱数组(数组;洗牌;随机)

384. 打乱数组 - 力扣(LeetCode)

发布:2021年9月18日13:55:42

问题描述及示例

给你一个整数数组 nums ,设计算法来打乱一个没有重复元素的数组。

实现 Solution class:
Solution(int[] nums) 使用整数数组 nums 初始化对象
int[] reset() 重设数组到它的初始状态并返回
int[] shuffle() 返回数组随机打乱后的结果

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shuffle-an-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

示例:
输入
[“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 * 104 次 reset 和 shuffle

我的题解

题目的核心就在于“随机”这个概念,而在计算机程序语言中实现的随机,其实是一般都是一种伪随机。如果真的要自己实现一种真正的随机算法估计得花费好一番功夫深入研究,所以我觉得还是直接用语言自身提供随机算法比较好。

shuffle() 方法中,先将原始数组拷贝一份为 copy,然后随机获取 copy 中的一个元素,将其从 copy 数组中删除,并将删除的结果压入存放结果的 shuffledArr 中。重复这个操作,直到 copy 数组为空。

详细解释请看下方注释:

/**
 * @param {number[]} nums
 */
var Solution = function(nums) {
  // 在创建的solution实例对象身上绑定一个变量orgin,代表原始的数据,且这个数据不被改变
  this.origin = nums;
};

/**
 * Resets the array to its original configuration and return it.
 * @return {number[]}
 */
Solution.prototype.reset = function() {
  // 因为我们设定实例对象上的origin是不会改变的,所以直接将其返回即可
  return this.origin;
};

/**
 * Returns a random shuffling of the array.
 * @return {number[]}
 */
Solution.prototype.shuffle = function() {
  // 将实例身上的origin拷贝一份,防止origin被修改,
  // 注意这里的展开运算符和解构赋值操作实现的是深拷贝效果,详情请看下方【补充】
  let copy = [...this.origin];
  //  shuffledArr用于存储原始数组被随机打乱顺序后所得到的结果
  let shuffledArr = [];
  // 当copy数组不为空时
  while(copy.length) {
    // 用Math.random()函数从copy数组中随机选取一个下标,
    // 并将该下标对应元素从copy中删除,同时将删除的元素压入shuffledArr
    shuffledArr.push(copy.splice(Math.random()*copy.length, 1));
  }
  // 当copy中的数组都被取完之后,shuffledArr中的结果就是随机打乱后的结果
  return shuffledArr;
};

/**
 * Your Solution object will be instantiated and called as such:
 * var obj = new Solution(nums)
 * var param_1 = obj.reset()
 * var param_2 = obj.shuffle()
 */


提交记录
执行结果:通过
10 / 10 个通过测试用例
执行用时:256 ms, 在所有 JavaScript 提交中击败了43.44%的用户
内存消耗:53.7 MB, 在所有 JavaScript 提交中击败了14.77%的用户
时间:2021/09/18 14:00	

主要还是借用原生的 Math.random() 函数来产生一个随机数。当然还有所谓的洗牌算法,但是感觉那种算法也是要建立在原生的伪随机的基础上的。所以这里就不深入说明了。下方的官方题解中就有相关的说明。

补充
这里用到了展开运算符和解构赋值。因为数组中的元素都是数字,也就是JavaScript中的基本类型之一,所以这里利用展开运算符做解构赋值时实现的其实是一种深拷贝的效果。如果数组中的元素是引用类型的,那就是浅拷贝。相关规范可参看下方文档:

参考:展开语法 - JavaScript | MDN
参考:解构赋值 - JavaScript | MDN

官方题解

更新:2021年7月29日18:43:21

因为我考虑到著作权归属问题,所以【官方题解】部分我不再粘贴具体的代码了,可到下方的链接中查看。

更新:2021年9月18日13:59:53

参考:打乱数组 - 打乱数组 - 力扣(LeetCode)

【更新结束】

有关参考

更新:2021年9月18日13:58:58
参考:展开语法 - JavaScript | MDN
参考:解构赋值 - JavaScript | MDN
参考:Array.prototype.splice() - JavaScript | MDN
参考:Math.random() - JavaScript | MDN
参考:用扩展运算符进行深拷贝的注意事项 - SegmentFault 思否

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值