用python解决混乱的字谜题?

时间:2010-07-28 08:02:59

标签: python algorithm

我有一个有趣的编程难题:

您将获得两件事:

  1. 包含英语单词列表的单词,例如:

    word = "iamtiredareyou"
    
  2. 可能的子集:

    subsets = [
       'i', 'a', 'am', 'amt', 'm', 't', 'ti', 'tire', 'tired', 'i', 
       'ire', 'r', 're', 'red', 'redare', 'e', 'd', 'da', 'dar', 'dare', 
       'a', 'ar', 'are', 'r', 're', 'e', 'ey', 'y', 'yo', 'you', 'o', 'u'
    ]
    
  3. 挑战:

    等级1:我需要务实地找到subsets中的成员,这些成员将按顺序排列"iamtiredareyou",即['i', 'am', 'tired', 'are', 'you']

    Level-2:原始字符串可能包含序列中的一些额外字符,这些字符在子集中不存在。例如"iamtired12aareyou"。给定的subset与上面相同,解决方案应该自动将此子集包含在结果数组中的正确位置。即['i', 'am', 'tired', '12a', 'are', 'you']

    我该怎么做?

6 个答案:

答案 0 :(得分:3)

通常,递归算法会这样做。 首先检查所有子集以防止给定单词的开始(如果找到) - 添加(追加)到找到的值并递归单词的剩余部分和当前找到的值。 或者,如果它是字符串的结尾 - 打印找到的值。

类似的东西:

all=[]
def frec(word, values=[]):
    gobal all
    if word == "":  # got result.
        all+=[values]
    for s in subsets:
        if word.startswith(s):
            frec(word[len(s):], values+[s])

frec(word)

请注意,由于子集包含许多单字符字符串,因此存在许多可能的解决方案。您可能希望找到一些最短的结果。 (13146解决方案......使用“all.sort(cmp = lambda x,y:cmp(len(x),len(y)))”来获得最短的时间

对于level2 - 如果没有子集匹配,则需要另一个循环,这会将越来越多的符号添加到下一个值(并递归到该值),直到找到匹配为止。

all=[]
def frec(word, values=[]):
    global all
    if word == "":  # got result.
        all+=[values]
        return true
    match = False
    for s in subsets:
        if word.startswith(s):
            match = True
            frec(word[len(s):], values+[s])       
    if not match:                        
        return frec(word[1:], values+[word[0]])
frec(word)

但这并不是试图将非子集值组合成一个字符串。

答案 1 :(得分:2)

我认为你应该做自己的编程练习....

答案 2 :(得分:1)

对于1级挑战,你可以recursively。可能不是最有效的解决方案,但最简单:

word = "iamtiredareyou"
subsets = ['i', 'a', 'am', 'amt', 'm', 't', 'ti', 'tire', 'tired', 'i', 'ire', 'r', 're', 'red', 'redare', 'e', 'd', 'da', 'dar', 'dare', 'a', 'ar', 'are', 'r', 're', 'e', 'ey', 'y', 'yo', 'you', 'o', 'u']

def findsubset():
    global word

    for subset in subsets:
        if word.startswith(subset):
            setlist.append(subset)
            word = word[len(subset):]

            if word == "":
                print setlist
            else:
                findsubset()

            word = subset + word
            setlist.pop()

# Remove duplicate entries by making a set
subsets = set(subsets)
setlist = []
findsubset()

您的子集列表中有重复项 - 例如'a'出现两次 - 因此我的代码会在搜索结果之前删除重复项set

答案 3 :(得分:1)

很抱歉缺少编程代码段,但我想建议动态编程。通过给每个单词一个成本,并添加不作为单个字符高成本单词存在的所有单个字符,同时攻击级别1和级别2。接下来的问题是找到将序列拆分成总成本最低的单词的方法。

沿着序列从左到右工作,在每个点处工作并保存最低成本解决方案,包括当前点,以及结束该解决方案的单词的长度。要计算序列中下一个点的答案,请考虑所有已知的序列后缀的单词。对于每个这样的单词,通过将该单词的成本添加到该单词开始之前结束的最佳解决方案的(已经计算出来的)成本,计算出最佳总成本。请注意最小的总成本和产生它的单词的长度。

一旦你获得整个序列的最佳成本,使用该序列中最后一个单词的长度来计算出最后一个单词是什么,然后退回那个字符数来检查那个时候得出的答案并在最后一个单词之前得到这个词,依此类推。

答案 4 :(得分:0)

是不是只是找到排列,但有一些条件?就像你启动排列算法(一个递归算法)一样,你检查你已经拥有的字符串是否匹配你找到单词的前X个字符,如果是,你继续递归直到你找到整个单词,否则你回去。

如果你问我,2级有点傻,因为那时你实际上可以写任何东西作为“要找到的词”,但基本上它就像level1一样,但如果你找不到子串在你的列表中你只需添加它(逐个字母即你有“爱”和['l','e']列表你匹配'l'但你缺少'o'所以你添加它并检查是否有任何你在列表中的单词以'v'开头,并且匹配你要找到的单词,他们不会这样你将'v'添加到'o'等。)

如果你觉得无聊,你可以实现一个遗传算法,它真的很有趣,但效率不高。

答案 5 :(得分:0)

这是一个递归,低效的Java解决方案:

private static void findSolutions(Set<String> fragments, String target, HashSet<String> solution, Collection<Set<String>> solutions) {
    if (target.isEmpty()) {
        solutions.add(solution);
        return;
    }

    for (String frag : fragments) {
        if (target.startsWith(frag)) {
            HashSet<String> solution2 = new HashSet<String>(solution);
            solution2.add(frag);
            findSolutions(fragments, target.substring(frag.length()), solution2, solutions);
        }
    }       
}

public static Collection<Set<String>> findSolutions(Set<String> fragments, String target) {
    HashSet<String> solution = new HashSet<String>();
    Collection<Set<String>> solutions = new ArrayList<Set<String>>();
    findSolutions(fragments, target, solution, solutions);
    return solutions;
}