如何进一步优化这个python脚本?

时间:2012-07-20 10:27:00

标签: python optimization micro-optimization

我已经创建了这个脚本来计算python中的string similarity。有什么方法可以让它跑得更快吗?

tries = input()
while tries > 0:
    mainstr = raw_input()
    tot = 0
    ml = len(mainstr)
    for i in xrange(ml):
        j = 0
        substr = mainstr[i:]
        ll = len(substr)
        for j in xrange(ll):
            if substr[j] != mainstr[j]:
                break
            j = j + 1
        tot = tot + j
    print tot
    tries = tries - 1

编辑:应用了一些优化后,这就是代码,但这还不够!

tries = int(raw_input())
while tries > 0:
    mainstr = raw_input()
    tot = 0
    ml = len(mainstr)
    for i in xrange(ml):
        for j in xrange(ml-i):
            if mainstr[i+j] != mainstr[j]:
                break
            j += 1
        tot += j
    print tot
    tries = tries - 1

编辑2 :代码的第三个版本。它仍然没有去!

def mf():
    tries = int(raw_input())
    for _ in xrange(tries):
        mainstr = raw_input()
        tot = 0
        ml = len(mainstr)
        for i in xrange(ml):
            for j in xrange(ml-i):
                if mainstr[i+j] != mainstr[j]:
                    break
                j += 1
            tot += j
        print tot
mf()

4 个答案:

答案 0 :(得分:2)

您可以跳过循环内的内存分配。 substr = mainstr[i:]不必要地分配新字符串。您只能在substr[j] != mainstr[j]中使用它,相当于mainstr[i + j] != mainstr[j],因此您不需要构建substr

内存分配很昂贵,因此您希望在紧密循环中避免使用它们。

答案 1 :(得分:2)

如果您使用i = mainstr.find(mainstr[0], i+1)而不是检查所有i,则可以通过常数因子对其进行改进。 i == 0的特例也可以提供帮助。

将代码放在函数中。它也可以通过一个恒定的因素加快速度。

使用for ... else: j += 1避免在每一步增加j

尝试找到比O(n ** 2)更好的算法,该算法利用了比较字符串所有后缀的事实。

最多straight-forward C implementation比CPython快100倍(Pypy快10-30倍)并通过挑战:

import os

def string_similarity(string, _cp=os.path.commonprefix):
    return sum(len(_cp([string, string[i:]])) for i in xrange(len(string)))

for _ in xrange(int(raw_input())):
    print string_similarity(raw_input())

上述优化仅提供了几个百分点的改进,并且它们不足以在CPython中传递挑战(Python时间限制只有8倍大)。

在CPython之间几乎没有区别:

def string_similarity(string):
    len_string = len(string)
    total = len_string # similarity with itself
    for i in xrange(1, len_string):
        for n, c in enumerate(string[i:]):
            if c != string[n]:
                break
        else:
            n += 1

        total += n
    return total

def string_similarity(string):
    len_string = len(string)
    total = len_string # similarity with itself
    i = 0
    while True:
        i = string.find(string[0], i+1)
        if i == -1:
            break
        n = 0
        for n in xrange(1, len_string-i):
            if string[i+n] != string[n]:
                break
        else:
            n += 1

        total += n
    return total

答案 2 :(得分:1)

对于这样的简单数字脚本,您只需要做两件事:

  • 使用PyPy(它没有复杂的依赖关系,速度会快得多)

  • 将大部分代码放在一个函数中。这大大加快了CPython和PyPy的速度。而不是:

    some_code

做的:

def main():
    some_code

if __name__ == '__main__':
    main()

这就是它。

干杯, fijal

答案 3 :(得分:0)

这是我的。它通过了测试用例,但可能不是绝对最快的。

import sys

def simstring(string, other):
    val = 0
    for l, r in zip(string, other):
        if l != r:
            return val
        val += 1
    return val


dsize = sys.stdin.readline()

for i in range(int(dsize)):
    ss = 0
    string = sys.stdin.readline().strip()
    suffix = string
    while suffix:
        ss += simstring(string, suffix)
        suffix = suffix[1:]
    sys.stdout.write(str(ss)+"\n")