Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python-查找可以在单词内部找到的所有子单词_Python_Algorithm - Fatal编程技术网

Python-查找可以在单词内部找到的所有子单词

Python-查找可以在单词内部找到的所有子单词,python,algorithm,Python,Algorithm,最后,我想找出英语词典中哪一个词包含的子词最多,至少有三个字母。我写了这个算法,但它太慢了,没有用处。想知道如何优化它吗 def subWords(word): return set((word[0:i] for i in range(2, len(word)+1))) #returns all subWords of length 2 or greater def checkDict(wordList, dictList): return set((word for word

最后,我想找出英语词典中哪一个词包含的子词最多,至少有三个字母。我写了这个算法,但它太慢了,没有用处。想知道如何优化它吗

def subWords(word):
    return set((word[0:i] for i in range(2, len(word)+1))) #returns all subWords of length 2 or greater

def checkDict(wordList, dictList):
    return set((word for word in wordList if word in dictList))

def main():
    dictList = [i.strip() for i in open('wordlist.txt').readlines()]
    allwords = list()
    maximum = (0, list())

    for dictWords in dictList:
        for i in range (len(dictWords)):
            for a in checkDict(subWords(dictWords[i: len(dictWords) + 1]), dictList):
                allwords.append(a)

        if len(allwords) > maximum[0]:
            maximum = (len(allwords), allwords)

        print maximum
        allwords = list()

    print maximum 
main()

这就是你要问的还是我遗漏了什么

>>> words = ['a', 'asd', 'asdf', 'bla']
>>> [sum(1 for i in (a for a in words if a in b)) for b in words]
[1, 2, 3, 2]
这是每个单词中的单词数。如果你不想计算少于3个字符的单词,只需删除它们

当然,它是O(n²)

编辑:

该问题要求所有子词,但代码只要求包含更多子词的子词。。。如果您真的想要第一种行为,只需删除
sum(…)
部分,并使genexp成为一个列表理解…

1)样式和组织:使用一个函数生成一个单词的所有子单词更有意义

2) 样式:使用
set
不需要双括号

3) 性能(我希望):也从正在查找的单词中设置一个
set
;然后可以使用内置的集合交点检查

4) 性能(几乎可以肯定):不要手动循环以找到最大元素;使用内置的
max
。您可以直接比较(长度、元素)元组;Python从头到尾按每对元素比较元组,就像每个元素都是字符串中的字母一样

5) 性能(可能):确保字典中没有一个字母或两个字母的单词作为开头,因为它们只是碍事

6) 性能(可悲的事实):不要将一切分解为一个函数

7) 样式:文件I/O应该使用带有块的
,以确保正确清理资源,默认情况下,文件迭代器迭代行,因此我们可以隐式获得行列表,而不必调用
.readlines()

我最终得到了(除了“片段”表达式外,没有正确测试):


您的算法的主要缺点是,对于每个子词,您需要将其与字典中的每个其他词进行比较。你真的不需要这样做——如果你的单词以“a”开头,你真的不需要看它是否匹配以“b”开头的单词。如果下一个字母是“c”,那么你就不想把它和以“d”开头的单词进行比较了。问题变成了:“我如何有效地实施这个想法?”

为此,我们可以创建一个树来表示字典中的所有单词。我们通过提取字典中的每个单词并用它扩展树,并在最后一个节点中着色来构造这棵树

当我们想要测试一个子词是否在这棵树中时,我们只需逐个字母地遍历这个词,并使用这些字母来确定下一个在树中的位置(从顶部开始)。如果我们发现我们无处可去,或者在遍历整个子单词后,我们降落在一个无阴影的树节点上,那么它就不是一个单词。否则,如果我们降落在阴影节点上,它就是一个单词。这样做的效果是我们可以一次搜索整个词典,而不是一次搜索一个单词。当然,这样做的代价是一开始就有一点设置,但是如果你在字典里有很多单词,这不是一个好的代价

那太棒了!让我们尝试实现它:

class Node:
    def __init__( self, parent, valid_subword ):
        self.parent = parent
        self.valid_subword = valid_subword
        self.children = {}

    #Extend the tree with a new node
    def extend( self, transition, makes_valid_word ):
        next_node = None
        if transition in self.children:
            if makes_valid_word:
                self.children[transition].makes_valid_word = True
        else:
            self.children[transition] = Node( self, makes_valid_word )
        return self.children[transition]

def generateTree( allwords ):
  tree = Node( None, False )
    for word in allwords:
      makes_valid_word = False
      current_node = tree
      for i in range(len(word)):
        current_node = current_node.extend( word[i], True if i == len(word) - 1 else False )
  return tree

def checkDict( word, tree ):
    current_node = tree
    for letter in word:
        try:
            current_node = current_node.children[letter]
        except KeyError:
            return False

    return current_node.valid_subword
然后,稍后:

for word in allWords:
  for subword in subWords(word):
    checkDict(subword)
    #Code to keep track of the number of words found, like you already have

此算法允许您在O(m)时间内检查词典中是否有单词,其中m是词典中最长单词的长度。请注意,对于包含任意数量单词的词典,该值大致保持不变。您最初的算法是每次检查O(n),其中n是字典中的单词数。

这将在几秒钟内运行。“sowpods.txt”包含3个或更多字母的267627个单词 如果您使用的是Python2.5或2.6,那么您需要使用
至少\u 3=set(如果len(w)>=3,则w表示w)

子字的最大数目是26

(26, 'CORESEARCHERS')
(26, 'FOREGONENESSES')
(26, 'METAGENETICALLY')
(26, 'PREPOSSESSIONS')
(26, 'SACRAMENTALISTS')
(26, 'WHOLESOMENESSES')

要探索基本Python,请看一下这个函数(基本上是JBernardo和Karl Knechtel建议的更快、更完善、更令人满意的版本):

输出类似于:

('greatgrandmothers',
set(['and', 'rand', 'great', 'her', 'mothers', 'moth', 'mother', 'others', 'grandmothers', 'grandmother', 'ran', 'other', 'greatgrandmothers', 'greatgrandmother', 'grand', 'hers', 'the', 'eat']))
对于来自的单词列表



现在我知道你不是在追求性能(上面的代码是你已经在任何地方使用集合了,除了它的作用:
如果dictList中的单词
应该是
如果dictSet中的单词
顺便说一句,你的描述是“三个字母,”你的代码是2。因为我甚至不知道那东西是做什么的。@hop那么你应该学一点python…
sum(1代表i in…
非常常见,意思是
len(iterable)
我对这个习语非常熟悉。这个答案并没有告诉我们什么是好的编码风格,也没有试图弄清楚发生了什么,也没有试图遵循OP的代码,可能也不会很快解决问题。这是Waaaay卓越的答案!这非常有效!谢谢你提供的所有提示。另外,你能解释一下如何解决问题吗代码的片段部分是有效的。在一个集合中如何有for循环?这是生成器理解吗?为什么选择使用range(i+3)?这是一个生成器理解,在两个计数器上迭代。
j
i+3
开始,因为
i
标记单词的开头,而
j
标记单词的结尾。挑剔:这是一个生成器表达式,与列表、集合或字典理解相反。生成器作为迭代器访问,而编译器作为迭代器访问nsion只是构造容器的一种特殊语法。算法不错,但我敢打赌它对python来说太低级了。在
set
s中查找时,可能会出错太多,python可能会更快。不知道您的代码是否有效,但对于手绘图片Azing图片和解释+1
(26, 'CORESEARCHERS')
(26, 'FOREGONENESSES')
(26, 'METAGENETICALLY')
(26, 'PREPOSSESSIONS')
(26, 'SACRAMENTALISTS')
(26, 'WHOLESOMENESSES')
def check_dict(word, dictionary): 
  """Return all subwords of `word` that are in `dictionary`."""
  fragments = set(word[i:j] 
                  for i in xrange(len(word) - 2) 
                  for j in xrange(i + 3, len(word) + 1))
  return fragments & dictionary

dictionary = frozenset(word for word in word_list if len(word) >= 3)
print max(((word, check_dict(word, dictionary)) for word in dictionary), 
          key=lambda (word, subwords): len(subwords)) # max = the most subwords
('greatgrandmothers',
set(['and', 'rand', 'great', 'her', 'mothers', 'moth', 'mother', 'others', 'grandmothers', 'grandmother', 'ran', 'other', 'greatgrandmothers', 'greatgrandmother', 'grand', 'hers', 'the', 'eat']))