这是一些比您的方法更有效的 Python,尽管仍然是指数级的(对不起,不知道 PHP):
from collections import Counter
def instancekey(letters):
return tuple(sorted(Counter(letters).values()))
memo = {}
def permcount(letters):
if not letters:
return 1
key = instancekey(letters)
count = memo.get(key)
if count is None:
count = 0
for letter, lettercount in Counter(letters).items():
rest = letters
for i in range(lettercount):
j = rest.find(letter)
rest = rest[:j] + rest[j + 1:]
if i % 2 == 0:
count += permcount(rest)
else:
count -= permcount(rest)
memo[key] = count
return count
这里有两个想法。第一种是通过包含-排除递归地执行计数。对于输入中的每个字母,我们累积以该字母开头的可能性数量。天真地,计算剩余字母的可能性就足够了,但这并没有强制执行前两个字母相等的约束。因此我们应用了一个修正——减去两个字母被删除的可能性的数量。这种修正本身就需要修正,由此我们得出了包含-排除公式。
第二个想法是使用记忆化来显着减少函数评估的数量。给定一个词PQRDDDEEEEFFFFF
,我们数
P: 1
Q: 1
R: 1
D: 3
E: 4
F: 5
然后删除字母(因为它们无关紧要)并对值进行排序:
1,1,1,3,4,5.