题目链接:LeetCode 384 打乱数组
题目大意:
给你一个整数数组\(nums\),设计算法来打乱一个没有重复元素的数组。打乱后,数组的所有排列应该是等可能的。
题解:
参考自LeedCode官方题解
首先,我们考虑如何随机打乱一个数组。
不妨设数组\(nums\),其长度为\(n\)。我们可以使用如下方法打乱:
- 将数组中所有的数都放到数据结构\(waiting\)中,并初始化打乱后的数组\(shuffle\);
- 循环\(n\)次,在第\(i\)次循环中\((0 \leq i < n)\):
- 在\(waiting\)中随机抽取一个数\(num\),将其作为打乱后的数组\(shuffle\)的第\(i\)个元素;
- 从\(waiting\)中移除\(num\)。
对于原数组\(nums\)中的数\(num\)来说,被移动到打乱后的数组的第\(i\)个位置的概率为:
\[p[i]=
\left\{
\begin{array}{l}
(\frac{n-1}{n} \times \frac{n-2}{n-1} \times ... \times \frac{n-i}{n-i+1}) \times \frac{1}{n-i} = \frac{1}{n}, i>0 \\
\frac{1}{n}, i = 0
\end{array}
\right.
\]
因此,对于原数组\(nums\)中的任意一个数,被移动到打乱后的数组的任意一个位置的概率都是相同的。
class Solution {
private:
vector<int> nums;
vector<int> orgins;
public:
Solution(vector<int>& nums) {
this->nums = nums;
this->orgins.resize(nums.size());
copy(nums.begin(), nums.end(), orgins.begin());
}
vector<int> reset() {
copy(orgins.begin(), orgins.end(), nums.begin());
return nums;
}
vector<int> shuffle() {
vector<int> shuf(orgins.size());
copy(orgins.begin(), orgins.end(), shuf.begin());
for (int i = 0; i < orgins.size(); ++i) {
int index = rand() % shuf.size();
vector<int>::iterator it = shuf.begin();
advance(it, index);
nums[i] = *it;
shuf.erase(it);
}
return nums;
}
};