问题描述
|
由于主题区域(写在墙上)添加了有趣的条件-字母无法更改其顺序,因此这不是关于字谜的问题。
我看到一个长字,用油漆写在墙上,现在突然
我希望通过画出字母的任意组合可以从该单词中得到所有可能的单词和短语。可以,用空格随机分隔。
为了扩大可能的结果,让我们假设,空格不需要分隔单词。
编辑:显然应该保持字母顺序(感谢idz指出这一点)。同样,短语可能毫无意义。这里有些例子:
Source word: disestablishment
paint out: ^ ^^^ ^^^^ ^^
left: i tabl e -> i table
or paint out:^^^^^^^^^ ^ ^^
left: ish e -> i she (spacelessness is ok)
视觉例子
困难模式/奖励任务:考虑可能对字母进行细微改动(D <-> B,C <-> O等)
请提出您解决此问题的方法。
这是我一般简单的方法
显然,我们需要英语词典来查找单词。
我们的目标是让单词在字典中进行搜索。
我们需要找到所有可能的字母变体,以使其与字典匹配:每个字母可以是本身(1)或涂成油漆(0)。
考虑到“不需要用空格来分隔单词”的情况,为了区分单词,我们必须假设任意两个字母之间都可能有空格(1-有空格,0-没有空格) 。
d i s e s t a b l i s h m e n t
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ - possible whitespace
N
=源词中的字母数
N-1
=可能的空格数
任何“ 4”元素都可以处于两种状态,因此让我们将它们视为布尔值。可能的变化数量为2^(N + N - 1)
。是的,它包括无用的变体,例如在空格之间粘贴空格,但是我没有提出更优雅的公式。
现在我们需要一个算法来获取布尔值的N+N-1
序列的所有可能的变体(我还没有想到,但是单词递归贯穿我的脑海)。然后用对应的字母(如果布尔值的索引为奇数)或空格(偶数)替换所有1。
和0,带空格(奇数)或无(偶数)。然后修剪开头和结尾的空格,分离单词并在字典中搜索它们。
我不喜欢这种怪异的方法,希望您能帮助我找到好的选择。
解决方法
1)将字典放入特里树或前缀树
2)通过在字符串中的每个位置查找合法词;存放这些
3)打印所有非重叠词的组合
假设与问题中的示例一样,您想要保持字母顺序(即您对字谜不感兴趣)。
,
#!/usr/bin/python3
from itertools import *
from pprint import pprint as pp
在字典中阅读,删除我们从未使用过的所有1个字母和2个字母的单词:
with open(\'/usr/share/dict/words\') as f:
english = f.read().splitlines()
english = map(str.lower,english)
english = [w for w in english if (len(w)>2 or w in [\'i\',\'a\',\'as\',\'at\',\'in\',\'on\',\'im\',\'it\',\'if\',\'is\',\'am\',\'an\'])]
def isWord(word):
return word in english
你的问题:
def splitwords(word):
\"\"\"
splitwords(\'starts\') -> ((\'st\',\'ar\',\'ts\'),(\'st\',\'arts\'),(\'star\',(\'starts\'))
\"\"\"
if word==\'\':
yield ()
for i in range(1,len(word)+1):
try:
left,right = word[:i],word[i:]
if left in english:
for reading in list(splitwords(right)):
yield (left,) + tuple(reading)
else:
raise IndexError()
except IndexError:
pass
def splitwordsWithDeletions(word):
masks = product(*[(0,1) for char in word])
for mask in masks:
candidate = \'\'.join(compress(word,mask))
for reading in splitwords(candidate):
yield reading
for reading in splitwordsWithDeletions(\'interesting\'):
print(reading)
结果(大约需要30秒):
()
(\'i\',)
(\'in\',)
(\'tin\',)
(\'ting\',)
(\'sin\',)
(\'sing\',)
(\'sting\',)
(\'eng\',)
(\'rig\',)
(\'ring\',)
(\'rein\',)
(\'resin\',)
(\'rest\',\'i\')
(\'rest\',\'in\')
...
(\'inters\',\'tin\')
(\'inter\',\'sting\')
(\'inters\',\'ting\')
(\'inter\',\'eng\')
(\'interest\',)
(\'interest\',\'i\')
(\'interest\',\'in\')
(\'interesting\',)
加速可能是通过预先计算每个字母可以读取的单词,每个字母分成一个bin,然后对预先计算的单词进行迭代以加快速度。我认为其他人会概述解决此问题的方法。
,您还可以在其他地方找到字谜算法。
subwords(word):
if word is empty return
if word is real word:
print word
anagrams(word)
for each letter in word:
subwords(word minus letter)
编辑:射击,您将希望在for循环中传递一个起点。否则,您将多余地创建很多呼叫。弗兰克减r减n与弗兰克减n减r相同。提出一个起点可以确保您获得每个子集一次...由于双字母重复导致的重复。也许只是在打印之前将结果记忆在哈希表中?啊...