大家好,我是Python进阶。这篇文章的标题实在是太难选了,干脆先取这个,装个13.前言前几天在彩哥交流群里,一个叫[RickXiang]的粉丝问了一个关于排列组合的问题Python交流群。乍一看似乎很简单,但实际上确实很难。题目是:一个列表中有15个没有重复值的随机数。从列表中随机选择5个数字,如何选择包括a、a+1在内的所有组合。a可以是15个数字中的任何一个。1.思路这道题看似简单。思维方式就像[先生。张]在上图中说。它可以分两步完成。理论上,确实是可以实现的。通常我们计算排列组合公式,使用下图中的组合公式是没有问题的。不过这个题目的实现涉及到一个Python程序的实现。当然,Python和我们计算一个值并不难。本文借用群友[有点意思]提到的蒙特卡洛算法和代码来实现。一起来看看吧!这是[先生提到的第二个方案。张],先随机取14个数,然后从14个随机数中随机选择一个,然后加1作为第15个随机数,再从15个随机数中随机选择5个随机数,然后进行if判断看连续值是否同时存在于同一个列表中,然后将满足条件的列表追加到一个空列表中,最后使用集合set去重得到最终结果。2、解决方案1)伪代码这里先给出[有点意思]老大的伪代码,这样大家看起来更容易理解,如下图。事实上,下面的代码不是伪代码。现在Python也支持中文变量了。下面的代码也可以运行,不过看起来比下面的纯英文代码更容易理解。下面给出具体的实现过程,这里给出5段代码,欢迎大家积极尝试。2)代码1#coding:utf-8importrandomdefquchong(list_data):list2=[]foriinlist_data:ifinotinlist2:list2.append(i)returnlist2#从15个随机数中随机取出5个数放入数组#生成不重复的14随机数random_14=[random.randint(0,100)foriinrange(14)]#这种写法容易出现重复随机值random_14=random.sample(range(100),14)print(random_14)random_1=random。选择(random_14)random_2=random_1+1random_14.append(random_2)random_15=random_14print(random_1,random_2)final_list=[]foriinrange(100):select=[random.choice(random_15)forjinrange(5)]quchong_select=set(select)ifrandom_1inquchong_selectandrandom_2inquchong_select:final_list.append(quchong_select)fina_result=quchong(final_list)print(len(fina_result))这个方法乍一看确实可以实现,但是这里会有一个小bug,就是random.randint()函数生成会有重复的值,题目要求是生成不重复的随机值。那么这个问题将在代码2中得到解决。3)代码2使用了random.sample()函数,可以随机生成随机值,不重复,非常nice。另外,使用numpy.random.choice()函数,可以直接选择5个随机数,比代码1效率更高。#-*-coding:utf-8-*-importnumpyasnpimportrandomdefquchong(list_data):list2=[]foriinlist_data:ifinotinlist2:list2.append(i)returnlist2#从15个随机值中随机取5个数放入数组#生成14个随机数random_14=random.sample(range(100),14)print(random_14)random_1=random.choice(random_14)random_2=random_1+1random_14.append(random_2)random_15=random_14print(random_1,random_2)final_list=[]foriinrange(100):sub_random_data=np.random.choice(random_15,5)quchong_select=set(sub_random_data)ifrandom_1inquchong_selectandrandom_2inquchong_select:final_list.append(quchong_result)fina_result=quchong(list)_final(4)代码3代码3主要是增加了一些功能在Code1和Code2的基础上,阅读起来更有逻辑性和层次感。#-*-coding:utf-8-*-#modularimportrandomimportnumpyasnp#从15个随机值中随机取出5个数,放入数组中,生成14个不重复的随机数defget_random15():random_14=random.sample(range(1000),14)print(random_14)random_1=random.choice(random_14)random_2=random_1+1random_14.append(random_2)random_15=random_14print(random_1,random_2)get_final_result(random_1,random_15)_defget(random_14)random_1,random_2,random_15):final_list=[]foriinrange(1000):sub_random_data=np.random.choice(random_15,5)quchong_select=set(sub_random_data)ifrandom_1inquchong_selectandrandom_2inquchong_select(final_list.append=quchong_s)len(fina_result))defquchong(list_data):list2=[]foriinlist_data:ifinotinlist2:list2.append(i)returnlist2if__name__=='__main__':get_random15()5)代码4细心的朋友可能发现了random取值时的问题np.random.choice(random_15,5),重复的值也会被取出来,同样不符合requirements。这里有一个方案,在取出15个随机数中的一个之后,然后从剩下的列表中取出取出的数,就完美的避免了这个问题。#modularimportrandomimportnumpyasnp#取出15个随机值defget_random15():foriinrange(2):random_15=random.sample(range(20),15)#print(random_15)get_random5(random_15)#遍历15个随机值,取两个相邻的随机数,并调用函数处理defget_random5(random_15):random_5=[]#遍历5次,从random_15中取5个不同的元素foriinrange(5):random_data=np.random.choice(random_15)random_5.append(random_data)random_15.remove(random_data)#print(random_5)fornuminrandom_5:random_1=numrandom_2=random_1+1get_final_result(random_1,random_2,random_5)#判断相邻两个值中是否有15个随机值在列表中,如果要求满足,保存在列表中,调用去重函数defget_final_result(random_1,random_2,random_5):final_list=[]ifrandom_1inrandom_5andrandom_2inrandom_5:print(random_5)final_list.append(random_1)result=quchong(final_list)print(result)#Deduplicate所有获得的列表defquchong(list_data):list=[]foriinlist_data:ifinotinlist:list.append(i)returnlistif__name__=='__main__':get_random15()代码写到这里,比前面的方案好多了,比前面三个代码更严谨,但是有仍然是不足之处。虽然解决了随机生成重复性的问题,也解决了从random_15中随机取出重复数的问题,但是缺点还是存在的。这段代码遍历比较多,复杂度正常,但是输出格式不太好看,没有达到预期。这里我只是遍历了2次,我只把随机数开到了0-20。如果循环次数增加,取值个数增加,计算速度就不好说了。6)Code5经过老大和我的共同努力,现已发布终极版。这个版本是迄今为止针对这个问题写的最严谨的版本。代码如下。#-*-coding:utf-8-*-#modularimportrandomimportnumpyasnpimporttime#取出15个随机值defget_random15():foriinrange(100000):random_15=random.sample(range(2000),15)#print("random15numbers=",random_15,len(random_15))get_random5(random_15)#遍历15个随机值,取两个相邻的随机数,调用函数处理defget_random5(random_15):random_5=[]#traverse5第二,取5来自random_15foriinrange(5)的不同元素:random_data=np.random.choice(random_15)random_5.append(random_data)random_15.remove(random_data)#print("random_5=",random_5)#print("random_15=",random_15)fornuminrandom_5:random_1=numrandom_2=random_1+1#print(random_1,random_2)get_final_result(random_1,random_2,random_5)#判断15个随机值的列表中是否同时存在两个相邻值,如果满足要求,保存在列表中,调用去重函数defget_final_result(random_1,random_2,random_5):final_list=[]ifrandom_1inrandom_5andrandom_2inrandom_5:#print(random_5)final_list.append(random_5)result=曲冲(final_list)ifresult:iflen(result[0])==5:#print(random_1,random_2)#print("result=",result)final_result.append(结果)#needle对所有得到的list进行去重defquchong(list_data):list=[]foriinlist_data:ifinotinlist:list.append(i)returnlistif__name__=='__main__':start_time=time.time()globalfinal_resultfinal_result=[]get_random15()final_result=quchong(final_result)print("一共有%d个列表符合题意"%len(final_result))print("分别为:%s"%final_result)end_time=time.time()used_time=end_time-start_timeprint()print("Timespentspentinthisprogram:{}".format(time.strftime('%H(hour):%M(minute):%S(second)',time.gmtime(used_time))))这段代码之后运行,可以看到满足题意的具体列表个数,以及具体的列表值,测试耗时。10万次循环内,约有1000条数据符合要求,运行时间仅为秒级。如果继续扩大循环,程序的复杂度会更大,更接近理论的排列组合值。因为耗时太长,这里就不做测试了。有兴趣的可以改参数调试。3.总结我是Python进阶。本文根据爱好者对排列组合的疑问,给出了使用Python基础+蒙特卡洛算法的解决方案,基本可以满足爱好者的要求。但话虽如此,该方案还是存在一定的弊端。随着循环次数的增加和随机数的增加,排列组合的次数也会增加,运行时间也会变长。当然,得到的数据会更加准确。准确的。
