我正在尝试解决this programming riddle,虽然解决方案(请参见下面的代码)正常工作,但成功提交速度太慢了。
基本上,手头的任务是:
GIVEN: L = [2,3,4,5,6,7,8,9,10,11,........] 1. Take the first remaining item in list L (in the general case 'n'). Move it to the 'lucky number list'. Then drop every 'n-th' item from the list. 2. Repeat 1 TASK: Calculate the n-th number from the 'lucky number list' ( 1 <= n <= 3000)
我的原始代码(它在我的机器上计算了大约一秒钟内的3000个第一个幸运数字 - 不幸的是太慢了):
"""
SPOJ Problem Set (classical) 1798. Assistance Required
URL: http://www.spoj.pl/problems/ASSIST/
"""
sieve = range(3, 33900, 2)
luckynumbers = [2]
while True:
wanted_n = input()
if wanted_n == 0:
break
while len(luckynumbers) < wanted_n:
item = sieve[0]
luckynumbers.append(item)
items_to_delete = set(sieve[::item])
sieve = filter(lambda x: x not in items_to_delete, sieve)
print luckynumbers[wanted_n-1]
编辑:感谢 Mark Dickinson,Steve Jessop和gnibbler的出色贡献,我得到了以下内容,这比我原来的代码快得多(并且成功地在{ {3}} 0.58秒!)......
sieve = range(3, 33810, 2)
luckynumbers = [2]
while len(luckynumbers) < 3000:
if len(sieve) < sieve[0]:
luckynumbers.extend(sieve)
break
luckynumbers.append(sieve[0])
del sieve[::sieve[0]]
while True:
wanted_n = input()
if wanted_n == 0:
break
else:
print luckynumbers[wanted_n-1]
答案 0 :(得分:7)
此系列称为 ludic numbers
__delslice__
应该比__setslice__
+ filter
>>> L=[2,3,4,5,6,7,8,9,10,11,12]
>>> lucky=[]
>>> lucky.append(L[0])
>>> del L[::L[0]]
>>> L
[3, 5, 7, 9, 11]
>>> lucky.append(L[0])
>>> del L[::L[0]]
>>> L
[5, 7, 11]
所以循环变为。
while len(luckynumbers) < 3000:
item = sieve[0]
luckynumbers.append(item)
del sieve[::item]
在不到0.1秒的时间内运行
答案 1 :(得分:4)
尝试使用这两行进行删除和过滤,而不是使用它们; filter(None, ...)
的运行速度比filter(lambda ...)
快得多。
sieve[::item] = [0]*-(-len(sieve)//item)
sieve = filter(None, sieve)
编辑:更好地使用del sieve[::item]
;见gnibbler的解决方案。
您也可以为while循环找到更好的终止条件:例如,如果筛子中的第一个剩余项目是i
,那么筛子的第一个i
元素将变为下一个i
个幸运数字;所以如果len(luckynumbers) + sieve[0] >= wanted_n
你应该已经计算出你需要的数字了 - 你只需要确定它在sieve
中的位置,以便你可以提取它。
在我的机器上,以下版本的内循环运行速度比原始版本快15倍,以找到第3000个幸运数字:
while len(luckynumbers) + sieve[0] < wanted_n:
item = sieve[0]
luckynumbers.append(item)
sieve[::item] = [0]*-(-len(sieve)//item)
sieve = filter(None, sieve)
print (luckynumbers + sieve)[wanted_n-1]
答案 2 :(得分:2)
可以找到有关如何解决此问题的说明here。 (我链接的问题要求更多,但该问题的主要步骤与您尝试解决的问题相同。)我链接的站点也包含C ++中的示例解决方案。
这组数字可以用二叉树表示,它支持以下操作:
n
元素n
元素可以实现这些操作以在O(log n)
时间运行,其中n
是树中节点的数量。
要构建树,您可以创建一个自定义例程,从给定的元素数组构建树,或者实现插入操作(确保树保持平衡)。
树中的每个节点都需要以下信息:
有了这样的结构,解决问题的其余部分应该相当简单。
我还建议在读取任何输入之前计算所有可能输入值的答案,而不是计算每个输入行的答案。
上述算法的Java实现在您链接的网站上在0.68秒内被接受。
(很抱歉没有提供任何特定于Python的帮助,但希望上面列出的算法足够快。)
答案 3 :(得分:1)
最好使用数组并使用该策略清空每个第N个项目;在连续几次执行此操作后,更新开始变得棘手,因此您需要重新构建阵列。这应该将速度提高至少10倍。你需要比这更好吗?
答案 4 :(得分:0)
为什么不创建一个新列表?
L = [x for (i, x) in enumerate(L) if i % n]