简介
- 该算法用于求解给定一个序列,如何在原地将原始序列随机打乱,并返回打乱后的结果。
算法思路
- 例如对于数组序列
n
u
m
s
[
0
]
,
n
u
m
s
[
1
]
,
n
u
m
s
[
2
]
,
n
u
m
s
[
3
]
,
⋯
n
u
m
s
[
n
−
1
]
nums[0],nums[1],nums[2],nums[3],\cdots nums[n - 1]
nums[0],nums[1],nums[2],nums[3],⋯nums[n−1]而言,假设当前处理的位置为i(从0开始).迭代执行如下步骤,知道i指向n-1:
- 随机生成一个[i,n-1]之间的随机数,设为j
- 将nums[j]与nums[i]进行交换。
- i++
证明思路:
往证第j个元素处于第i个位置的概率为
1
n
\frac{1}{n}
n1
事件等价于i之前的位置j都未被交换过去,恰好第i个位置与j被交换。
p
(
第
j
个元素处于第
i
个位置
)
=
(
1
−
1
n
)
(
1
−
1
n
−
1
)
⋯
(
1
−
1
n
−
i
+
2
)
1
n
−
i
+
1
=
1
n
p(第j个元素处于第i个位置)=(1 - \frac{1}{n})(1 - \frac{1}{n-1})\cdots (1 - \frac{1}{n-i+2})\frac{1}{n-i+1} = \frac{1}{n}
p(第j个元素处于第i个位置)=(1−n1)(1−n−11)⋯(1−n−i+21)n−i+11=n1
即证
典型实例-leetcode Shuffle an Array
class Solution {
int[] origin;
Random rand = new Random();
public Solution(int[] nums) {
origin = nums;
}
/**
* 将数组冲i新设置到原有的形式
* @return
*/
public int[] reset() {
return origin;
}
public int[] shuffle() {
//原始数组的返回结果
int[] ret = new int[this.origin.length];
System.arraycopy(this.origin,0,ret,0,origin.length);
//交换origin中的元素作为ret的返回结果
for(int i = 0;i < origin.length;i++)
{
//随机生成一个随机数
int picked = rand.nextInt(origin.length - i) + i;
int temp = ret[picked];
ret[picked] = ret[i];
ret[i] = temp;
}
return ret;
}
}