Python的速度差异

时间:2015-07-31 14:01:26

标签: python performance python-2.7

我最近试图在Hackerrank上解决this problem。我最终得到了以下解决方案,在给定的时间限制内给出了正确的答案:

from collections import Counter
lisa=[]
for each in range(input()):
    current=raw_input()
    count=0
    lookup_dict={}
    i=0
    for i in range(len(current)):
        for j in range(i,len(current)):
            sub_string=current[i:j+1]
            sub_string=''.join(sorted(sub_string))
            if sub_string in lookup_dict.keys():
                lookup_dict[sub_string]+=1
            else:
                lookup_dict[sub_string]=1

    for k in lookup_dict.values():
        count+=k*(k-1)/2
    print count

我的问题是他们提供的解决方案(下面再现)明显快于我写的解决方案,即使使用的复杂性和方法是相同的。

from collections import *
for i in range(input()):
    s = raw_input()
    check = defaultdict(int)
    l = len(s)
    for i in range(l):
        for j in range(i+1,l+1):
            sub = list(s[i:j])
            sub.sort()
            sub = "".join(sub)
            check[sub]+=1
    sum = 0
    for i in check:
        n = check[i]
        sum += (n*(n-1))/2
    print sum

我的猜测是它与defaultdict方法有关,但无法找出原因?

2 个答案:

答案 0 :(得分:4)

在Python 2.x中,dict.keys()返回一个列表,在您的第一个解决方案中,您实际上正在执行 -

if sub_string in lookup_dict.keys()

这将是一个O(n)操作(n是dictonary的大小 - lookup_dict),因为.keys()实际返回一个列表,并且包含检查列表是O(n),也是最有可能是必须创建列表的额外成本。

而在第二种方法中,您没有任何此类检查,而defaultdict正在处理为您自动设置默认值,这可能是您的第一个解决方案明显慢于第二个解决方案的原因之一(鉴于此你在最里面的循环中进行dict.keys()查找,以便多次查找。

显示dict.keys()返回列表的示例 -

>>> d = {1:2,3:4,5:6,7:8}
>>> d.keys()
[1, 3, 5, 7]

答案 1 :(得分:1)

谈论defaultdict:与普通密钥检查相比,它的优化程度。即:

x = defaultdict(int)
for i in xrange(...):
    x[i] += 1

快〜50%
x = {}
for i in xrange(...):
    if i in x:
         x[i] +=1
    else:
        x[1] = 1

如果缺少所有键的情况。

但主要的情况是在py2中调用dict.keys()实际上会创建一个列表。因此,检查key in dict.keys()需要首先为列表分配内存,然后使用实际键值填充它,然后检查您的密钥。最糟糕的是,在此列表应该由垃圾收集器清理之后,在下一个for步骤中,您将执行相同的操作,除了将为该列表分配更多内存。所以,在你的例子中,这实际上会扼杀性能。