题目描述
打乱一个没有重复元素的数组。
示例:
// 以数字集合 1, 2 和 3 初始化数组。
int[] nums = {1,2,3};
Solution solution = new Solution(nums);
// 打乱数组 [1,2,3] 并返回结果。任何 [1,2,3]的排列返回的概率应该相同。
solution.shuffle();
// 重设数组到它的初始状态[1,2,3]。
solution.reset();
// 随机返回数组[1,2,3]打乱后的结果。
solution.shuffle();
解题思路:国内没考过,偏数学:「随机乱置算法」或者「洗牌算法」。看看就好。
// 得到一个在闭区间 [min, max] 内的随机整数
int randInt(int min, int max);
// 第一种写法
void shuffle(int[] arr) {
int n = arr.length();
/******** 区别只有这两行 ********/
for (int i = 0 ; i < n; i++) {
// 从 i 到最后随机选一个元素
int rand = randInt(i, n - 1); // 注意这里一定是rand和i交换
/*************************/
swap(arr[i], arr[rand]);
}
}
// 洗牌算法,或者说随机乱置算法的正确性衡量标准是:对于每种可能的结果出现的概率必须相等,也就是说要足够随机。
/** 分析洗牌算法正确性的准则:产生的结果必须有 n! 种可能,否则就是错误的。**这个很好解释,因为一个长度为 n 的数组的全排列就有 n! 种,也就是说打乱结果总共有 n! 种。算法必须能够反映这个事实,才是正确的。**/
参考代码
class Solution {
public:
vector<int> nums;
vector<int> copy;
Solution(vector<int>& nums) {
this->nums = nums;
this->copy.assign(nums.begin(), nums.end());
}
/** Resets the array to its original configuration and return it. */
vector<int> reset() {
nums.clear();
nums.assign(copy.begin(), copy.end());
return nums;
}
/** Returns a random shuffling of the array. */
vector<int> shuffle() {
for (int i = nums.size() - 1; i >= 0; --i)
{
srand(clock()); // 参考https://blog.csdn.net/u013745804/article/details/82379266
swap(nums[rand() % (i + 1)], nums[i]);
}
return nums;
}
};
/**
* Your Solution object will be instantiated and called as such:
* Solution* obj = new Solution(nums);
* vector<int> param_1 = obj->reset();
* vector<int> param_2 = obj->shuffle();
*/