我需要找到给定字符串的所有子字符串的字谜。我使用以下代码找到了给定字符串的所有可能的子字符串:
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']
我想从此列表中找到长度相等的子字符串,如果它们是字谜。有什么想法吗?
答案 0 :(得分:0)
如果两个字符串是字谜,它们必须具有相同的长度,则可以使用简单的嵌套for
循环直接对其进行测试。
要检查两个字符串是否为字谜,collections.Counter
会派上用场:它计算可迭代元素中每个不同元素的出现次数,因此两个字符串si
和sj
是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 是子字符串的数量。