洗牌问题
题目内容
题目: 手里面n张不同牌面的牌,编写一个洗牌程序,让随机取出一张牌的概率相同。
要求: 说明算法思路、分析时间复杂度、用Array编写洗牌程序、编写测试用例。
算法思路
时间复杂度
时间复杂度应该为:O(n)
实现程序
下面给出4种实现方法、比较各种方法的好坏,其中shuffle_best(cards)是上面算法分析的实现。
import random
def shuffle_system(cards):
random.shuffle(cards) # 官方给你的shuffle函数
import random
def shuffle_1st(cards):
for k in range(len(cards)):
i = random.randint(0,len(cards)-1) # 随机取出一张
j = random.randint(0,len(cards)-1) # 随机取出一张
cards[i], cards[j] = cards[j], cards[i] # 两张交换
import random
def shuffle_2nd(cards):
for k in range(len(cards)):
i = random.randint(0,len(cards)-1) # 随机取出一张
cards[i], cards[k] = cards[k], cards[i] # 两张交换
最好的解法:
randomi = i + random.randint(0,(len(cards) - i -1)) ,此处 i +保证了前面放好的了牌不会被取到。
import random
def shuffle_best(cards):
for i in range(len(cards)):
randomi = i + random.randint(0,(len(cards) - i -1)) # 从剩下的随机取出一张
cards[i], cards[randomi] = cards[randomi], cards[i] # 依次取出的和从剩余中随机取出的交换
测试用例
def test_shuffle(f):
result = [[0 for i in range(0,10)] for j in range(0,10)]
for i in range(10000):
A = [i for i in range(0,10)]
f(A)
for j in range(len(A)):
result[A[j]][j] += 1 # 第j张牌在第j个位置
print("\n".join([''.join(['{:6}'.format(item) for item in row])for row in result]))
用官方给出的shuffle接口,每张牌出现的概率大都为1/10,符合要求。
第一种洗牌程序,主对角线上的概率为2/10,不是很理想。
第二种洗牌程序,主对角线下面的元素也不是很理想,我们想要的是都在1000次左右。
第三种洗牌程序,每张牌在每个位置出现的位置的次数都接近1000,相比1st 和 2nd 的情况要好一点,是我们想要。