Python 从字典中找到句子的字谜的有效方法?
我需要制作一个程序,将带有字典和任意字符串的文件作为输入,然后输出该字典中组成给定字符串的所有单词组合。 例如,使用英语中最流行的100个单词和字符串Python 从字典中找到句子的字谜的有效方法?,python,optimization,combinations,anagram,Python,Optimization,Combinations,Anagram,我需要制作一个程序,将带有字典和任意字符串的文件作为输入,然后输出该字典中组成给定字符串的所有单词组合。 例如,使用英语中最流行的100个单词和字符串“我不工作”,我应该得到类似[“在it上工作”,“投入工作”,“不工作”,“知道或它”,“工作它不”,“在”],我就是这样做的 问题是我的程序效率太低:字典中有100个单词,实际限制是字符串长度为7个字符,之后的所有操作都需要花费太长的时间。我试着寻找与这件事相关的各种算法,但都无济于事 以下是我如何搜索字谜: def sortstring(str
“我不工作”
,我应该得到类似[“在it上工作”,“投入工作”,“不工作”,“知道或它”,“工作它不”,“在”]
,我就是这样做的
问题是我的程序效率太低:字典中有100个单词,实际限制是字符串长度为7个字符,之后的所有操作都需要花费太长的时间。我试着寻找与这件事相关的各种算法,但都无济于事
以下是我如何搜索字谜:
def sortstring(string):
return ''.join(sorted(string))
def simplify(all_strings):
possible_strings = defaultdict(list)
for string in all_strings:
possible_strings[sortstring(string).strip()].append(string)
return possible_strings
def generate(database, length,curstring="", curdata=set()):
if len(curstring.replace(" ", "")) > length:
return set()
if len((curstring).replace(" ", "")) == length:
return curdata.union(set([curstring]))
for i in database:
if len((curstring+i).replace(" ", "")) <= length:
curdata = curdata.union(generate(database.difference(set([i])),
length, curstring+" "+i, curdata))
database = database.difference(set([i]))
return curdata
def analyse(database, input_string):
cletters = countstring(input_string)
strings = simplify(generate(database, cletters))
data = list()
sorted_string = sortstring(input_string).strip()
if sorted_string in strings.keys():
data = strings[sorted_string]
return len(strings.values()), data
def countstring(string):
a = countletters(string)
return sum(a.values())
def countletters(string):
result = {}
for i in ascii_lowercase:
result[i] = string.count(i)
return result
def排序字符串(字符串):
返回“”。联接(已排序(字符串))
def简化(所有_字符串):
可能的\u字符串=defaultdict(列表)
对于所有_字符串中的字符串:
可能的_字符串[sortstring(string).strip()].append(string)
返回可能的\u字符串
def generate(数据库,长度,curstring=”“,curdata=set()):
如果len(curstring.replace(“,”)>长度:
返回集()
如果len((curstring).replace(“,”)==长度:
返回curdata.union(set([curstring]))
对于数据库中的i:
如果len((curstring+i).replace(“,”)我自己解决了部分问题。
已解决生成器代码中if反模式的问题:
def generate(database, length,letters,curstring="",curdata=set()):
if len(curstring.replace(" ",""))>length:
return set()
if len((curstring).replace(" ",""))==length:
return curdata.union(set([curstring]))
t=countletters(curstring)
for i in ascii_lowercase:
if t[i]>letters[i]:
return set()
for i in database:
t=countletters(curstring+i)
test=0
for j in ascii_lowercase:
if t[j]>letters[j]:
test=1
if test: continue
if sum(t.values())<=length:
curdata=curdata.union(generate(database.difference(set([i])),length,letters,curstring+" "+i,curdata))
database=database.difference(set([i]))
return curdata
def generate(数据库、长度、字母、curstring=”“,curdata=set()):
如果len(curstring.replace(“,”)>长度:
返回集()
如果len((curstring).replace(“,”)==长度:
返回curdata.union(set([curstring]))
t=计数字母(粗字符串)
对于ascii_小写形式的i:
如果t[i]>字母[i]:
返回集()
对于数据库中的i:
t=计数字母(粗字符串+i)
测试=0
对于ascii_小写形式的j:
如果t[j]>字母[j]:
测试=1
如果测试:继续
如果sum(t.values())这里有一个递归方法,实现我在评论中建议的树方法:
def frequencyDict(s):
s = s.lower()
d = {}
for c in s:
if c.isalpha():
if c in d:
d[c] += 1
else:
d[c] = 1
return d
def canMake(w,fdict):
d = frequencyDict(w)
return all(d[c] <= fdict.get(c,0) for c in d)
def candidates(wlist,fdict):
return [w for w in wlist if canMake(w,fdict)]
def anagrams(wlist,fdict):
if len(wlist) == 0 or len(fdict) == 0:
return "no anagrams"
hits = []
firstWords = candidates(wlist,fdict)
if len(firstWords) == 0:
return "no anagrams"
for w in firstWords:
#create reduced frequency dict
d = fdict.copy()
for c in w:
d[c] -= 1
if d[c] == 0: del d[c]
#if d is empty, the first word is also a the last word
if len(d) == 0:
hits.append(w)
else:
#create reduced word list
rlist = [v for v in wlist if canMake(v,d)]
tails = anagrams(rlist, d)
if tails != "no anagrams":
hits.extend(w + " " + t for t in tails)
if len(hits) == 0:
return "no anagrams"
else:
return hits
def findAnagrams(wlist,s):
return anagrams(wlist,frequencyDict(s.lower()))
f = open("linuxwords.txt")
words = f.read().split('\n')
f.close()
words = [w.strip().lower() for w in words if not '-' in w]
test = findAnagrams(words, "Donald Trump")
def频率记录:
s=s.下()
d={}
对于s中的c:
如果c.isalpha():
如果d中有c:
d[c]+=1
其他:
d[c]=1
返回d
def canMake(带fdict):
d=频率dict(w)
返回全部(d[c]一些测试:对于2个字母的字符串,生成时间为0.00085s,对于3个字母的字符串,生成时间为0.0039s,对于4个字母的字符串,生成时间为0.018s,对于5个字母的字符串,生成时间为0.05s,对于6个字母的字符串,生成时间为0.48s,对于7个字母的字符串,生成时间为4.2s编写一个函数,该函数标识可以由字符串的字母组成的所有单词,然后在回溯算法中使用该函数。类似于树遍历。空字符串是根。字典中可以由字母组成的单词是子单词。当您访问节点时,该节点的子单词是可以由m组成的单词从剩余的字母中删除。任何这样的单词也会出现在可能的单词列表中一级以上,因此您应该能够非常快地判断哪些单词仍然是可能的。如果您到达一个节点,其中存在无法形成任何单词的剩余字母,请返回轨迹。如果您到达一个节点,其中没有剩余的字母,则返回路径为r指向该节点的oot是您要寻找的字谜之一。您不必在每个阶段从头开始重新生成列表——当您沿着树向下移动时,您会扔掉可能的单词,您也不会添加新单词。整个词典只需处理一次。我美化了您的代码。空白的缺失伤害了我过于敏感的眼睛。它似乎更慢韩:我的当前实现。在一个2645字谜的例子中,程序花了大约3秒钟找到所有的字谜。@Mashalla我确信有优化。另外,我的代码找到所有有序的字谜(“damp nut lord”,“lord nut damp”,等等,所有3!=6)一种优化方法是编写一个函数,该函数返回多个集合,例如{'damp'、'nut'、'lord'}
,而不是字符串