Python 从字典中找到句子的字谜的有效方法?

Python 从字典中找到句子的字谜的有效方法?,python,optimization,combinations,anagram,Python,Optimization,Combinations,Anagram,我需要制作一个程序,将带有字典和任意字符串的文件作为输入,然后输出该字典中组成给定字符串的所有单词组合。 例如,使用英语中最流行的100个单词和字符串“我不工作”,我应该得到类似[“在it上工作”,“投入工作”,“不工作”,“知道或它”,“工作它不”,“在”],我就是这样做的 问题是我的程序效率太低:字典中有100个单词,实际限制是字符串长度为7个字符,之后的所有操作都需要花费太长的时间。我试着寻找与这件事相关的各种算法,但都无济于事 以下是我如何搜索字谜: def sortstring(str

我需要制作一个程序,将带有字典和任意字符串的文件作为输入,然后输出该字典中组成给定字符串的所有单词组合。 例如,使用英语中最流行的100个单词和字符串
“我不工作”
,我应该得到类似
[“在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'}
,而不是字符串