Algorithm 一种生成字谜的算法

Algorithm 一种生成字谜的算法,algorithm,language-agnostic,puzzle,Algorithm,Language Agnostic,Puzzle,生成字谜的最佳策略是什么 11+2是12+1的字谜 小数点是我是原地一个点的字谜 天文学家是对月球恒星的一种解读 起初,它看起来非常简单,只是把字母混在一起并生成所有可能的组合。但是,什么是只生成字典中的单词的有效方法呢 我偶然发现了这一页 但是你的想法是什么?在我看来,最有意义的解决方案是从输入字符串中随机选取一个字母,然后根据以该字母开头的单词过滤字典。然后选择另一个,过滤第二个字母,等等。此外,过滤掉不能用剩余文本生成的单词。然后,当你碰到一个单词的结尾时,插入一个空格,然后用剩下的字

生成字谜的最佳策略是什么

  • 11+2是12+1的字谜
  • 小数点我是原地一个点的字谜
  • 天文学家是对月球恒星的一种解读
起初,它看起来非常简单,只是把字母混在一起并生成所有可能的组合。但是,什么是只生成字典中的单词的有效方法呢

我偶然发现了这一页


但是你的想法是什么?

在我看来,最有意义的解决方案是从输入字符串中随机选取一个字母,然后根据以该字母开头的单词过滤字典。然后选择另一个,过滤第二个字母,等等。此外,过滤掉不能用剩余文本生成的单词。然后,当你碰到一个单词的结尾时,插入一个空格,然后用剩下的字母重新开始。您还可以根据单词类型限制单词(例如,您不会有两个动词相邻,两篇文章相邻等)。

对于词典中的每个单词,请按字母顺序排序。所以“foobar”变成了“abfoor”

然后当输入的字谜出现时,也对其字母进行排序,然后查找它与哈希表查找一样快

对于多个单词,您可以对已排序的字母进行组合,边走边排序。仍然比生成所有组合快得多

(有关更多优化和详细信息,请参见评论)

我的看法:

你可能想建立一个表格,将无序的字母集合映射到单词列表中,例如,浏览字典,这样你就可以

lettermap[set(a,e,d,f)] = { "deaf", "fade" }
然后,从起始单词中,您可以找到一组字母:

 astronomers => (a,e,m,n,o,o,r,r,s,s,t)
然后循环遍历该集合的所有分区(这可能是最技术性的部分,只是生成所有可能的分区),并查找该集合字母的单词

编辑:嗯,这是杰森·科恩发布的内容

编辑:此外,关于这个问题的评论提到生成“好的”字谜,如示例:)。在你建立了所有可能的字谜的列表之后,通过WordNet运行它们,并找到语义上与原始短语相近的字谜:)

  • 正如Jason所建议的,准备一个字典制作哈希表,关键字按字母顺序排序,并为单词本身赋值(每个关键字可能有多个值)
  • 在查询之前,请删除空白并对查询进行排序 在此之后,您需要进行某种递归的、彻底的搜索。伪代码非常粗略:

    function FindWords(solutionList, wordsSoFar, sortedQuery)
      // base case
      if sortedQuery is empty
         solutionList.Add(wordsSoFar)
         return
    
      // recursive case
    
      // InitialStrings("abc") is {"a","ab","abc"}
      foreach initialStr in InitalStrings(sortedQuery)
        // Remaining letters after initialStr
        sortedQueryRec := sortedQuery.Substring(initialStr.Length)
        words := words matching initialStr in the dictionary
        // Note that sometimes words list will be empty
        foreach word in words
          // Append should return a new list, not change wordSoFar
          wordsSoFarRec := Append(wordSoFar, word) 
          FindWords(solutionList, wordSoFarRec, sortedQueryRec)
    
    最后,您需要遍历solutionList,并在每个子列表中打印单词,单词之间留有空格。您可能需要打印这些案例的所有订单(例如,“我是山姆”和“山姆我是”都是解决方案)

    当然,我没有测试过,这是蛮力的方法。

    < P>参见华盛顿大学CSE系。

    基本上,您有一个数据结构,它只包含单词中每个字母的计数(数组适用于ascii,如果您需要unicode支持,请升级到映射)。您可以减去其中两个字母集;如果计数为负数,您知道一个单词不可能是另一个单词的拼音。

    预处理:

    构建一个trie,每个叶子作为一个已知单词,按字母顺序键入

    在搜索时:

    将输入字符串视为多集。在深度优先搜索中,通过遍历索引trie查找第一个子词。在每个分支机构,你都可以问,我输入的其余部分中是否有字母x?如果您有一个好的多集表示,这应该是一个固定时间查询(基本上)

    一旦有了第一个子词,就可以保留剩余的多集,并将其作为新的输入来查找该字谜图的其余部分(如果存在)

    通过记忆来扩充此过程,以便更快地查找公共余数多集


    这是相当快的-每个trie遍历保证给出一个实际的子字,并且每个遍历在子字的长度上花费线性时间(按照编码标准,子字通常非常小)。然而,如果你真的想要更快的东西,你可以在预处理中包含所有的n-gram,其中n-gram是一行中n个单词的任意字符串。当然,如果W=#words,那么您将从索引大小O(W)跳到O(W^n)。也许n=2是现实的,这取决于你字典的大小。

    几个月前,我使用了以下方法计算字谜:

    • 计算字典中每个单词的“代码”:创建一个从字母表中的字母到素数的查找表,例如,以['a',2]开始,以['z',101]结束。作为预处理步骤,通过在查找表中查找每个字母的素数并将它们相乘,计算字典中每个单词的代码。为便于以后查找,请创建代码到单词的多重映射

    • 如上所述,计算输入单词的代码

    • 为多重映射中的每个代码计算CodeIndicationary%inputCode。如果结果为0,则您已找到一个字谜,可以查找适当的单词。这也适用于2个或更多单词的字谜


    希望这会有帮助。

    乔恩·本特利(Jon Bentley)的《编程珍珠》(Programming Pearls)一书很好地涵盖了这类内容。必须阅读。

    不久前,我写了一篇关于如何快速找到两个单词的字谜的博客文章。它的工作速度非常快:在一个Ruby程序中,查找一个文本文件超过300000个单词(4兆字节)的单词的所有44个双字字谜只需0.6秒

    如果允许应用程序将单词列表预处理为从按字母排序的单词到按字母排序的单词列表的大型哈希映射,则可以加快应用程序的速度
    function FindWords(solutionList, wordsSoFar, sortedQuery)
      // base case
      if sortedQuery is empty
         solutionList.Add(wordsSoFar)
         return
    
      // recursive case
    
      // InitialStrings("abc") is {"a","ab","abc"}
      foreach initialStr in InitalStrings(sortedQuery)
        // Remaining letters after initialStr
        sortedQueryRec := sortedQuery.Substring(initialStr.Length)
        words := words matching initialStr in the dictionary
        // Note that sometimes words list will be empty
        foreach word in words
          // Append should return a new list, not change wordSoFar
          wordsSoFarRec := Append(wordSoFar, word) 
          FindWords(solutionList, wordSoFarRec, sortedQueryRec)
    
    // recursive function to find all the anagrams for charInventory characters
    // starting with the word at dictionaryIndex in dictionary keyList
    private Set<Set<String>> findAnagrams(int dictionaryIndex, char[] charInventory, List<String> keyList) {
        // terminating condition if no words are found
        if (dictionaryIndex >= keyList.size() || charInventory.length < minWordSize) {
            return null;
        }
    
        String searchWord = keyList.get(dictionaryIndex);
        char[] searchWordChars = searchWord.toCharArray();
        // this is where you find the anagrams for whole word
        if (AnagramSolverHelper.isEquivalent(searchWordChars, charInventory)) {
            Set<Set<String>> anagramsSet = new HashSet<Set<String>>();
            Set<String> anagramSet = new HashSet<String>();
            anagramSet.add(searchWord);
            anagramsSet.add(anagramSet);
    
            return anagramsSet;
        }
    
        // this is where you find the anagrams with multiple words
        if (AnagramSolverHelper.isSubset(searchWordChars, charInventory)) {
            // update charInventory by removing the characters of the search
            // word as it is subset of characters for the anagram search word
            char[] newCharInventory = AnagramSolverHelper.setDifference(charInventory, searchWordChars);
            if (newCharInventory.length >= minWordSize) {
                Set<Set<String>> anagramsSet = new HashSet<Set<String>>();
                for (int index = dictionaryIndex + 1; index < keyList.size(); index++) {
                    Set<Set<String>> searchWordAnagramsKeysSet = findAnagrams(index, newCharInventory, keyList);
                    if (searchWordAnagramsKeysSet != null) {
                        Set<Set<String>> mergedSets = mergeWordToSets(searchWord, searchWordAnagramsKeysSet);
                        anagramsSet.addAll(mergedSets);
                    }
                }
                return anagramsSet.isEmpty() ? null : anagramsSet;
            }
        }
    
        // no anagrams found for current word
        return null;
    }
    
    package com.vvirlan;
    
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileReader;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    import java.util.Scanner;
    
    public class Words {
        private int[] PRIMES = new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73,
                79, 83, 89, 97, 101, 103, 107, 109, 113 };
    
        public static void main(String[] args) {
            Scanner s = new Scanner(System.in);
            String word = "hello";
            System.out.println("Please type a word:");
            if (s.hasNext()) {
                word = s.next();
            }
            Words w = new Words();
            w.start(word);
        }
    
        private void start(String word) {
            measureTime();
            char[] letters = word.toUpperCase().toCharArray();
            long searchProduct = calculateProduct(letters);
            System.out.println(searchProduct);
            try {
                findByProduct(searchProduct);
            } catch (Exception e) {
                e.printStackTrace();
            }
            measureTime();
            System.out.println(matchingWords);
            System.out.println("Total time: " + time);
        }
    
        private List<String> matchingWords = new ArrayList<>();
    
        private void findByProduct(long searchProduct) throws IOException {
            File f = new File("/usr/share/dict/words");
            FileReader fr = new FileReader(f);
            BufferedReader br = new BufferedReader(fr);
            String line = null;
            while ((line = br.readLine()) != null) {
                char[] letters = line.toUpperCase().toCharArray();
                long p = calculateProduct(letters);
                if (p == -1) {
                    continue;
                }
                if (p == searchProduct) {
                    matchingWords.add(line);
                }
            }
            br.close();
        }
    
        private long calculateProduct(char[] letters) {
            long result = 1L;
            for (char c : letters) {
                if (c < 65) {
                    return -1;
                }
                int pos = c - 65;
                result *= PRIMES[pos];
            }
            return result;
        }
    
        private long time = 0L;
    
        private void measureTime() {
            long t = new Date().getTime();
            if (time == 0L) {
                time = t;
            } else {
                time = t - time;
            }
        }
    }