赞
踩
给你一个整数数组 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]]
有一个操作,对任意一个元素都可能发生,如果每个元素被操作的概率是相等的,那么这个操作才能公平的进行。
对于数组(长度为len)中每个数字,我们想方法将其中任意一个元素用1/len的概率(等可能)抽出来,然后len--,直到清空数组。我们将元素以拿出的先后顺序为依据形成一个排列,这就是一个公平的随机的排列。
Knuth算法就是一个以此过程对数组进行随机化操作。
先介绍C++random(#include <random>)库实现随机数的两个对象。
std::random_device,真随机数类,直接从机器设备中选一个数出来,速度较慢。
std::mt19937,是一个基于32位的梅森旋转算法的对象,生成一个伪随机数,速度较快。
std::random_device rd;实现了一个rd对象。此后每次调用rd()就会获得一个随机数。
std::mt9937 mt(rd()),从rd()调一个随机数作为种子实现了一个mt对象。此后每次调用mt()就会获得一个随机数。
在实际执行Knuth算法中,我们不需要真实取出一个元素,而是只需要初始化i=len-1,从前i+1个数(0,1,2,...i)随机选一个与第i个位置交换即可。
- //以------表示随机范围,以*表示取到
- i 0 1 2 3 4
- nums[i] 9 8 7 6 5
- i
- ----*----
- ↓
- nums[i] 9 8 5 6 7
- i
- ----*--
- ↓
- nums[i] 9 8 6 5 7
- i
- --*--
- ↓
- nums[i] 9 6 8 5 7
- i
- --*
- ↓
- nums[i] 9 6 8 5 7
- i
- *
- ↓
- nums[i] 9 6 8 5 7

- std::mt19937 mt;
- void Knuth(vector<int>&vec){
- const int len=vec.size();
- for(int i=len-1;i>0;i--)
- swap(vec[mt()%(i+1)], vec[i]);
- //取余操作+1是为了能取到i,因为第i个位置也在备选行列,自己与自己交换也在公平随机之内
- }
- class Solution {
- private:
- vector<int> val;
- mt19937 mt;
- const int len;
-
- public:
- Solution(vector<int>& nums) : val(nums), len(nums.size()){};
- vector<int> reset() { return val; }
- vector<int> shuffle() {
- vector<int> ans(val);
- Knuth(ans);
- return ans;
- }
- void Knuth(vector<int>& vec) {
- for (int i = len - 1; i > 0; i--)
- swap(vec[mt() % (i+1) ], vec[i]);
- }
- };

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。