计算给定字符串(字谜)的子字符串数

时间:2019-01-10 11:05:15

标签: python algorithm list-comprehension

我需要找到给定字符串的所有子字符串的字谜。我使用以下代码找到了给定字符串的所有可能的子字符串:

def anagrams(string):
    # abba
    subs = [string[i:j+1] for i in range(len(string)) for j in range(i, len(string))]
    # ['a', 'ab', 'abb', 'abba', 'b', 'bb', 'bba', 'b', 'ba', 'a']

我想从此列表中找到长度相等的子字符串,如果它们是字谜。有什么想法吗?

2 个答案:

答案 0 :(得分:0)

如果两个字符串是字谜,它们必须具有相同的长度,则可以使用简单的嵌套for循环直接对其进行测试。

要检查两个字符串是否为字谜,collections.Counter会派上用场:它计算可迭代元素中每个不同元素的出现次数,因此两个字符串sisj是anagram,如果和仅当Counter(si) == Counter(sj)时。

from collections import Counter

def anagrams(string):
    subs = [string[i:j+1] for i in range(len(string)) for j in range(i, len(string))]
    counters = list(map(Counter, subs))
    total = 0

    for i, ci in enumerate(counters):
        for j, cj in enumerate(counters):
            if i != j and ci == cj:
                total += 1

    return total

答案 1 :(得分:0)

与@MarcoBonelli答案一样,您可以使用collections.Counter创建字符串的表示形式,当且仅当字符串彼此相同,它们才是相等的,例如:

'bba' -> ('b', 2), ('a', 1)
'abb' -> ('b', 2), ('a', 1)

您可以使用字典将具有相同Counter表示形式的字符串分组并使用单个循环,而不是执行嵌套的for循环并检查每对配对:

from collections import Counter


def anagrams(string):
    subs = [string[i:j+1] for i in range(len(string)) for j in range(i, len(string))]

    anagrams = {}
    for si in subs:
        key = frozenset(Counter(si).items())
        anagrams.setdefault(key, []).append(si)

    # only want the groups with more than one element
    return list(value for value in anagrams.values() if len(value) > 1)


result = anagrams('abba')
print(result)

输出

[['abb', 'bba'], ['b', 'b'], ['ab', 'ba'], ['a', 'a']]

在输出中,子列表对应于彼此为字谜的字符串组。要在字典中使用计数器,您必须将项目转换为frozenset。最后,这种方法的复杂度为 O(n),其中 n 是子字符串的数量。