洗牌算法(打乱扑克牌顺序)

洗牌算法(打乱扑克牌顺序)

问题描述:有一个大小为 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))
posted @ 2021-01-06 14:01  刘桓湚  阅读(528)  评论(0编辑  收藏  举报