这个python代码可以更高效吗?

时间:2015-05-16 01:24:47

标签: python for-loop optimization time-complexity itertools

我编写了一些代码来查找字符串中有多少个子字符串是字符串对。查找anagram(anagramSolution)的函数具有复杂度O(N)。子串函数的复杂度小于N平方。但是,这里的代码就是问题所在。可以更优化吗?

for i in range(T):
    x = raw_input()
    alist = get_all_substrings(x)

    for k, j in itertools.combinations(alist,2):
        if(len(k) == len(j)):
            if(anagramSolution(k,j)):
                counter +=1

    counterlist.append(counter)
    counter = 0

alist可以包含数千个项目(子集)。 主要问题是循环。迭代所有项目需要花费大量时间。有没有更快或更有效的方法来做到这一点?

2 个答案:

答案 0 :(得分:6)

将字符串的 anagram类定义为每个字母在字符串中出现的次数的计数集。例如,'banana'具有anagram类a: 3, b: 1, n: 2。如果它们具有相同的anagram类,则两个字符串是彼此的字谜。我们可以计算每个anagram类中字符串的子串数,然后计算每个带有n个子串的anagram类的(n choose 2)对的数量:

from collections import Counter

anagram_class_counts = Counter()

for substring in get_all_substrings(x):
    anagram_class_counts[frozenset(Counter(substring).viewitems())] += 1

anagram_pair_count = sum(x*(x-1)/2 for x in anagram_class_counts.viewvalues())

frozenset(Counter(substring).viewitems())构建字符串的anagram类的可散列表示。

  • Counter采用可迭代的方式构建一个映射,表示每个项目出现的次数,所以
  • Counter(substring)构建一个表示字符串的anagram类的映射。
  • viewitems()提供类似于集合的集合:计数对和
  • frozenset将其转换为可用作dict键的不可变集。

这些步骤一起占用与子串大小成比例的时间;平均而言,子串大约是整个字符串大小的三分之一,因此平均而言,处理每个子字符串需要O(len(x))时间。有O(len(x)**2)个子字符串,因此处理所有子字符串需要O(len(x)**3)次。

如果x个子串具有相同的anagram类,则可以x*(x-1)/2方式对其进行配对,因此sum会查看每个anagram类的出现次数并计算对的数量。这需要O(len(x)**2)时间,因为它必须经过一次每个anagram类,并且不能有比字串更多的anagram类。

总的来说,这个算法需要O(len(x)**3)时间,这不是很好,但它比原来要好很多。仍然有优化空间的空间,例如通过利用子串之间的重叠或使用更有效的anagram类表示来计算anagram类。

答案 1 :(得分:1)

我不认为你可以完全逃避这个问题的迭代,但至少你可以让手头的任务减少一个因子O(2 ^ nC2 / 2 ^ n)。

您希望在开始迭代之前将子字符串分组为各自的长度,因为您要添加更多案例进行检查。

当前方法比较一组中的所有对,这需要2 ^ nC2 =比较。这是一个巨大的数字(2^n)! / ((2^n-2)! * 2!)

如果我们首先列出长度为1-n的子串然后进行比较,我们就花费:

  1. 2 ^ n操作遍历所有子字符串
  2. nC2操作通过长度为1的子字符串
  3. ...
  4. 也就是说,我们在对数方面做得更好。

    编辑:我意识到字符串不是集合,子字符串不是子集,但这只影响子集的数量而不影响主要参数。

相关问题