问题如题:N个人围城一圈报数(1/2/3/1/2/3/...),数到3的退出队列,求最后留下的人
#-*- coding:UTF-8 -*-
import time
def func1(n):
"""思路:删除原有列表中的凡是数到3及倍数的
使用临时序列存储要删除的数字,在每次循环完后删除需要去掉的数字"""
ltPserion = list(range(1,n+1))
pos = 0
while len(ltPserion)>1:
ltRemove = []
for i in ltPserion:
pos += 1
if pos%3==0:
ltRemove.append(i)
#print('ltPserion:',ltPserion,'将删除',ltRemove)
for i in ltRemove:
ltPserion.remove(i)
return ltPserion[0]
def func2(n):
"""思路:列表中凡是数到3及倍数
对于报数进行取余判断,如果是3的倍数就删除"""
ltPserion = list(range(1,n+1))
SayNo = 0
DelCount = 0
while DelCount<len(ltPserion)-1:
for i in range(len(ltPserion)):
if ltPserion[i] != 0:
SayNo+=1
if SayNo%3==0:
ltPserion[i]=0
#print('删除',ltPserion[i] ,ltPserion)
DelCount+=1
for i in ltPserion:
if i!=0:
return i
def func3(n):
"""思路:删除原有列表中的凡是数到3及倍数的
直接在原序列上操作,不中间列表存储要删除的数字"""
ltPserion = list(range(1,n+1))
SayNo = 0
DelCount = 0
i = 0
while len(ltPserion)>1:
SayNo += 1
#print(ltPserion, '索引i=',i ,'当前数数SayNo=', SayNo, '人', ltPserion[i], end='')
if SayNo%3 == 0:
#print('删除',ltPserion[i], end='')
ltPserion.remove(ltPserion[i])
i-=1
i+=1
if i>=len(ltPserion):
i=0
#print()
return ltPserion[0]
def func4(n):
"""思路:列表中凡是数到3的就标记为删除
不用%取余,直接用if判断大于3就从1开始数数"""
ltPserion = list(range(1,n+1))
SayNo = 0
DelCount = 0
while DelCount<len(ltPserion)-1:
for i in range(len(ltPserion)):
if ltPserion[i] != 0:
if SayNo==3:
SayNo = 1
else:
SayNo += 1
if SayNo==3:
ltPserion[i]=0
#print('删除',ltPserion[i] ,ltPserion)
DelCount+=1
for i in ltPserion:
if i!=0:
return i
def main():
N = 100000
starttime1 = time.clock()
rt1 = func1(N)
endtime1 = time.clock()
print('func1:',rt1, endtime1-starttime1)
starttime2 = time.clock()
rt2 = func2(N)
endtime2 = time.clock()
print('func2:', rt2, endtime2-starttime2)
starttime3 = time.clock()
rt3 = func3(N)
endtime3 = time.clock()
print('func3:',rt3, endtime3-starttime3)
starttime4 = time.clock()
rt4 = func4(N)
endtime4 = time.clock()
print('func4:',rt4, endtime4-starttime4)
pass
if __name__ == '__main__':
main()
执行结果如下
>>>
func1: 92620 39.25819919960245
func2: 92620 0.31389559593181104
func3: 92620 42.987894393368286
func4: 92620 0.30714721310604887
>>>
分析:
对于上面的问题,采用了4个方法处理,求得的结果是方法4效率最高。
func1和func3类似,都是处理的list,删除报数为3的人,而func3更慢一点的原因是“if i>=len(ltPserion):”每次循环都获取了一次人员列表的长度。
func2和func4都没有删除数到3的人,只是在原队列中标记了去除的人,效率高了100倍,有此可见,程序执行循环耗费的时间,比队列的元素的删除省不少运行时间。func4比func2效率高一点点的原因是func2中“if SayNo%3==0:”使用了取余,取余操作的效率不如“if SayNo==3:SayNo = 1; else: SayNo += 1;”效率高。
当然func2、func4比起func1、func3也有弊端,就是占用的内存,func1、func3运行内存会不断的减小,而func2、func4不会减小。
本文通过四种不同方法实现报数游戏(数到3的人退出)的算法,并对比其执行效率。结果显示,标记而非真正删除元素的方法能显著提高程序运行速度,尤其是避免使用取余运算。

985

被折叠的 条评论
为什么被折叠?



