我得到一系列字母,必须产生给定序列的所有N长度字谜,其中N是序列的长度。
我在python中遵循一种天真的方法,我正在采取所有的排列以实现这一目标。我发现了一些像this one这样的类似线程,但我更喜欢Python中的数学导向方法。那么对于排列来说,什么是更高效的替代方案呢?我在下面的尝试中有什么特别的错误吗?
from itertools import permutations
def find_all_anagrams(word):
pp = permutations(word)
perm_set = set()
for i in pp:
perm_set.add(i)
ll = [list(i) for i in perm_set]
ll.sort()
print(ll)
答案 0 :(得分:3)
如果有很多重复的字母,关键是只产生一次每个字谜,而不是产生所有可能的排列并消除重复。
这是一种可能只生成每个anagram一次的算法:
from collections import Counter
def perm(unplaced, prefix):
if unplaced:
for element in unplaced:
yield from perm(unplaced - Counter(element), prefix + element)
else:
yield prefix
def permutations(iterable):
yield from perm(Counter(iterable), "")
这实际上与产生所有排列的经典递归没有多大区别;唯一的区别是它使用collections.Counter(多重集)来保存尚未放置的元素而不是仅仅使用列表。
在迭代过程中产生的Counter
个对象的数量肯定是过多的,几乎可以肯定有更快的写入方式;我选择这个版本是为了它的简单性(希望)它的清晰度
答案 1 :(得分:1)
对于具有许多相似字符的长字,这非常慢。与理论上的最大性能相比较慢。例如,permutations("mississippi")
将生成比必要更长的列表。它的长度为39916800,但该组的大小为34650。
>>> len(list(permutations("mississippi")))
39916800
>>> len(set(permutations("mississippi")))
34650
所以你的方法的一大缺陷是你生成所有的字谜,然后删除重复。使用仅生成唯一字谜的方法。
编辑:
这是一些有效的,但非常丑陋且可能有错误的代码。当你读这篇文章时,我会让它变得更好。它确实为密西西比州提供了34650,所以我假设没有任何重大错误。再次警告。难看!
# Returns a dictionary with letter count
# get_letter_list("mississippi") returns
# {'i':4, 'm':1, 'p': 2, 's':4}
def get_letter_list(word):
w = sorted(word)
c = 0
dd = {}
dd[w[0]]=1
for l in range(1,len(w)):
if w[l]==w[l-1]:
d[c]=d[c]+1
dd[w[l]]=dd[w[l]]+1
else:
c=c+1
d.append(1)
dd[w[l]]=1
return dd
def sum_dict(d):
s=0
for x in d:
s=s+d[x]
return s
# Recursively create the anagrams. It takes a letter list
# from the above function as an argument.
def create_anagrams(dd):
if sum_dict(dd)==1: # If there's only one letter left
for l in dd:
return l # Ugly hack, because I'm not used to dics
a = []
for l in dd:
if dd[l] != 0:
newdd=dict(dd)
newdd[l]=newdd[l]-1
if newdd[l]==0:
newdd.pop(l)
newl=create(newdd)
for x in newl:
a.append(str(l)+str(x))
return a
>>> print (len(create_anagrams(get_letter_list("mississippi"))))
34650
它的工作方式如下:对于每个唯一的字母l,创建所有唯一的排列,少一个字母l的出现,然后将l附加到所有这些排列。
对于" mississippi",这比set(排列(单词))更快,并且它远非最佳写入。例如,字典很慢,并且在这段代码中可能需要改进很多东西,但它表明算法本身比你的方法快得多。
答案 2 :(得分:0)
也许我错过了什么,但你为什么不这样做:
from itertools import permutations
def find_all_anagrams(word):
return sorted(set(permutations(word)))
答案 3 :(得分:0)
答案 4 :(得分:0)
我不知道python但是我想尝试帮助你:可能还有很多其他更高性能的算法,但我已经考虑过这个:它完全是递归的,它应该覆盖所有的情况排列。我想从一个基本的例子开始:
ABC
的排列现在,这个算法以这种方式工作:对于Length
次,你向右移动字母,但最后一个字母将成为第一个字母(你可以用队列轻松地做到这一点)。
回到例子,我们将:
现在重复第一个(也是唯一一个)步骤,从第二个字母到最后一个字母构建子字符串。
不幸的是,使用此算法,您无法考虑重复排列。