减少字谜词搜索的计算时间

时间:2018-06-30 20:04:06

标签: python

以下代码是一种蛮力搜索方法,用于搜索单词列表并创建任何字母组合图的子列表。

搜索整个英语词典非常耗时,所以我很好奇有人可以降低代码的计算复杂度吗?

def anogramtastic(anagrms):
    d = []
    e = []
    for j in range(len(anagrms)):
        if anagrms[j] in e:
            pass
        else:
            templist = []
            tester = anagrms[j]        
            tester = list(tester)
            tester.sort()
            tester = ''.join(tester)
            for k in range(len(anagrms)):
                if k == j:
                    pass
                else:
                    testers = anagrms[k]        
                    testers = list(testers)
                    testers.sort()
                    testers = ''.join(testers)
                    if testers == tester:
                        templist.append(anagrms[k])
                        e.append(anagrms[k])
            if len(templist) > 0:
                templist.append(anagrms[j])
                d.append(templist)
    d.sort(key=len,reverse=True) 
    return d

print(anogramtastic(wordlist))

3 个答案:

答案 0 :(得分:3)

如何使用冻结集字典? Frozenset是不可变的,这意味着您可以对它们进行哈希处理以进行恒定查找。当涉及到字谜时,使两个单词字谜彼此对应的原因是它们具有相同的字母,且计数相同。因此,您可以构建{{letter,count),...}对的冻结集,并对其进行哈希处理以进行有效查找。

这是一个快速的小功能,可使用collections.Counter将单词转换为多集:

from collections import Counter, defaultdict

def word2multiset(word):
    return frozenset(Counter(word).items())

现在,给定单词列表,像这样填充字谜字典:

list_of_words = [... ]

anagram_dict = defaultdict(set)
for word in list_of_words:
    anagram_dict[word2multiset(word)].add(word)

例如,当list_of_words = ['hello', 'olleh', 'test', 'apple']时,这是运行以上循环后anagram_dict的输出:

print(anagram_dict)
defaultdict(set,
            {frozenset({('e', 1), ('h', 1), ('l', 2), ('o', 1)}): {'hello',
              'olleh'},
             frozenset({('e', 1), ('s', 1), ('t', 2)}): {'test'},
             frozenset({('a', 1), ('e', 1), ('l', 1), ('p', 2)}): {'apple'}})

答案 1 :(得分:3)

除非您对问题有误解,否则仅通过对单词的字符进行排序来对单词进行分组就应该是一种有效的解决方案-正如您已经意识到的那样。诀窍是避免将每个单词与所有其他单词进行比较。以字符排序的字符串为键的字典将使为每个单词快速找到正确的组;查找/插入将为O(log n)。

if(n == 0)
  return 0;
return log2(n & -n)+1;   //Assuming the bit index starts from 1

在我的word文件(99171个单词)上进行测试,似乎效果很好:

#!/usr/bin/env python3
#coding=utf8

from sys import stdin

groups = {}

for line in stdin:
    w = line.strip()
    g = ''.join(sorted(w))
    if g not in groups:
        groups[g] = []
    groups[g].append(w)

for g, words in groups.items():
    if len(words) > 1:
        print('%2d %-20s' % (len(words), g), ' '.join(words))

答案 2 :(得分:1)

使用字典检查成员资格而不是进行线性搜索,可以大大加快操作速度。唯一的“技巧”是设计一种为其创建密钥的方法,以使它与拼写单词(而不是其他单词)相同。

在下面的代码中,这是通过根据每个单词中的字母创建一个排序的元组来完成的。

def anagramtastic(words):
    dct = {}
    for word in words:
        key = tuple(sorted(word))  # Identifier based on letters.
        dct.setdefault(key, []).append(word)

    # Return a list of all that had an anagram.
    return [words for words in dct.values() if len(words) > 1]

wordlist = ['act', 'cat', 'binary', 'brainy', 'case', 'aces',
            'aide', 'idea', 'earth', 'heart', 'tea', 'tee']

print('result:', anagramtastic(wordlist))

产生的输出:

result: [['act', 'cat'], ['binary', 'brainy'], ['case', 'aces'], ['aide', 'idea'], ['earth', 'heart']]