我正在解决Euler项目上的问题26,需要计算1 / n重复部分的长度,其中n是1到1000之间的所有整数,并查看哪个数字是最长的重复部分。那意味着我需要我的部门做得更精确。因此,我通过更改getContext().prec
来提高自己的十进制精度,但是后来以某种方式提高了精度使程序更快了。我使用Python 3.7运行了该程序。这是代码:
import re
import time
s = time.time()
from decimal import *
getcontext().prec = 500 #This part
recurring = 0
answer = 0
p = re.compile(r"([0-9]+?)\1{3,}")
for i in range(1, 1000):
f = p.search(str(Decimal(1) / Decimal(i))[5:])
if f:
number = f.group(1)
if len(str(number)) > len(str(recurring)):
recurring = number
answer = i
print(answer)
print(time.time() - s)
这是我使用500精度时的结果:
>>> print(answer)
349
>>> print(time.time() - s)
2.923844575881958
...这就是我使用5000精度时得到的结果:
>>> print(answer)
983
>>> print(time.time() - s)
0.07812714576721191
我用500换了5000,不仅给了我正确的答案,因为1 / answer的重复部分可能比500长,而且速度也更快。我已经使用在线Python解释器进行了尝试,它也给了我类似的结果。为什么会这样?
答案 0 :(得分:2)
我使用了以下测试代码:
import time
import re
import string
t=time.time()
re.compile() # I tried differend regexes here
print(time.time()-t)
def test(n):
t=time.time()
match = rex.search(string.ascii_lowercase*n)
print(match, time.time()-t)
重新启动python会话后,对re.compile
的首次调用所花费的时间要长于相同正则表达式的后续编译。
compile(sec) search (sec)
REGEX 1st 2nd short long string
r"(abcdefghijklmnopqrstuvwxyz){6,}" 10^-4 10^-5 10^-5 10^-5
r"(abcdefghijklmnopqrstuvwxyz)\1\1\1\1" 10^-4 10^-5 10^-6 10^-6
r"([a-z]+?)\1\1\1\1" 10^-4 10^-5 10^-4 10^-5
r"([a-z]+)\1\1\1\1" 10^-4 10^-5 10^-4 10^-5
r"([a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z])\1\1\1\1"
10^-4 10^-5 10^-6 10^-6
有趣的是,对于字符串太短的情况,偶尔r"([a-z]+?)\1\1\1"
也会很快(10 ^ -5秒)。
编译rexex涉及一些缓存,但这不是这里的原因。
似乎组中的+
运算符(贪婪和非贪婪)与正则表达式中的\1
的组合是错误的。由于某种原因,如果实际匹配,则此组合比不匹配的组合要快。
要了解更多信息,我们可能必须了解sre
模块的C源代码
答案 1 :(得分:1)