洗牌算法(打乱扑克牌顺序)
洗牌算法(打乱扑克牌顺序)
问题描述:有一个大小为 n 的有序数组,如何打乱元素顺序,使得任一元素在数组的任一位置出现的概率都为 1/n?也就是说对于大小为 n 的有序数组,有 n!种排列方式,要求能等概率的得到这 n!种结果。
思路一:每次从原始数组中随机取一个之前未取过的元素,添加到新数组中。选取方法是:生成一个 1~rem 的随机数 i,rem 为还未添加的元素个数,将第 i 个元素添加到新数组中,然后从原始数组中删除该元素。
时间复杂度:
O
(
n
2
)
O(n^2)
O(n2)<br> 空间复杂度:
O
(
n
)
O(n)
O(n)
import random
def func(arr):
n = len(arr)
rem = n
new = []
for i in range(n):
p = random.randint(1, rem) # randint的随机范围是[a,b]闭区间
new.append(arr[p-1])
del arr[p-1]
rem -= 1
return new
if __name__ == '__main__':
arr = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
print(func(arr))
思路二:在思路一的基础上,其实不用每次都将原数组的元素删除,再添加进新的数组。只需要将选取的元素与当前数组的末尾元素交换即可,适用于允许更改原数组的情况。
时间复杂度:
O
(
n
)
O(n)
O(n)<br> 空间复杂度:
O
(
1
)
O(1)
O(1)
import random
def func(arr):
n = len(arr)
rem = n
for i in range(n):
p = random.randint(1, rem) # randint的随机范围是[a,b]闭区间
arr[p-1], arr[rem-1] = arr[rem-1], arr[p-1]
rem -= 1
return arr
if __name__ == '__main__':
arr = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
print(func(arr))
转载于网络 侵权联系作者立即删除QAQ