【问题标题】:Find all valid words when given a string of characters (Recursion / Binary Search)给定字符串时查找所有有效单词(递归/二进制搜索)
【发布时间】:2017-06-18 14:09:52
【问题描述】:

我想要一些关于我尝试实施但不能 100% 工作的方法的反馈。我正在制作一个 Android 应用程序来练习,其中给用户 20 个随机字母。然后,用户使用这些字母来制作任何大小的单词。然后它会检查字典以查看它是否是有效的英语单词。 给我带来麻烦的部分是显示“提示”。如果用户卡住了,我想显示可以做出的可能的话。我最初想到的是递归。但是,对于 20 个字母,这可能需要相当长的时间来执行。因此,我还实现了二进制搜索来检查当前递归路径是否是字典中任何内容的前缀。我确实得到了要输出的有效提示,但是它没有返回所有可能的单词。我的递归思维在这里有错误吗?另外,是否有推荐的更快的算法?我见过一种方法,您可以检查字典中的每个单词,看看字符是否可以组成每个单词。不过,我想知道我的方法与那个方法相比效果如何。

private static void getAllWords(String letterPool, String currWord) {
    //Add to possibleWords when valid word
    if (letterPool.equals("")) {
        //System.out.println("");
    } else if(currWord.equals("")){
        for (int i = 0; i < letterPool.length(); i++) {
            String curr = letterPool.substring(i, i+1);
            String newLetterPool = (letterPool.substring(0, i) + letterPool.substring(i+1));
            if(dict.contains(curr)){
                possibleWords.add(curr);
            }

            boolean prefixInDic = binarySearch(curr);
            if( !prefixInDic ){
                break;
            } else {
                getAllWords(newLetterPool, curr);
            }
        }
    } else {
        //Every time we add a letter to currWord, delete from letterPool
        //Attach new letter to curr and then check if in dict
        for(int i=0; i<letterPool.length(); i++){
            String curr = currWord + letterPool.substring(i, i+1);
            String newLetterPool = (letterPool.substring(0, i) + letterPool.substring(i+1));
            if(dict.contains(curr)) {
                possibleWords.add(curr);
            }
            boolean prefixInDic = binarySearch(curr);
            if( !prefixInDic ){
                break;
            } else {
                getAllWords(newLetterPool, curr);
            }
        }
    }

private static boolean binarySearch(String word){
    int max = dict.size() - 1;
    int min = 0;
    int currIndex = 0;
    boolean result = false;
    while(min <= max) {
        currIndex = (min + max) / 2;
        if (dict.get(currIndex).startsWith(word)) {
            result = true;
            break;
        } else if (dict.get(currIndex).compareTo(word) < 0) {
            min = currIndex + 1;
        } else if(dict.get(currIndex).compareTo(word) > 0){
            max = currIndex - 1;
        } else {
            result = true;
            break;
        }
    }
    return result;
}

【问题讨论】:

  • 你没有很好地解释你想要做什么。我建议用一个具体的例子来更新你的问题。例如,向用户显示字母“f e h s r a”,然后他们选择字母……等等。” 深入并端到端地解释整个示例。

标签: java recursion binary-search


【解决方案1】:

加快算法速度的最简单方法可能是使用Trie(前缀树)

Trie 数据结构提供了两种相关的方法。 isWord(String) 和 isPrefix(String),两者都进行 O(n) 比较以确定字典中是否存在单词或前缀(其中 n 是参数中的字母数)。这真的很快,因为你的字典有多大并不重要。

为了比较,您使用二进制搜索检查字典中是否存在前缀的方法是 O(n*log(m)),其中 n 是字符串中的字母数,m 是字典中的单词数.

我使用 Trie 编写了与您类似的算法,并将其与您在非常非正式的基准测试中发布的代码(稍作修改)进行了比较。 输入 20 个字符时,Trie 需要 9 毫秒。原始代码没有在合理的时间内完成,所以我不得不杀死它。

编辑: 至于为什么您的代码不返回所有提示,如果前缀不在您的字典中,您不想中断。您应该继续检查下一个前缀。

【讨论】:

    【解决方案2】:

    有推荐的更快的算法吗?

    请参阅有关“String searching algorithm”的 Wikipedia 文章,特别是名为“Algorithms using a finite set of patterns”的部分,其中“有限模式集”是您的字典。

    首先列出的Aho–Corasick algorithm 可能是一个不错的选择。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-24
      • 1970-01-01
      • 2019-03-29
      • 1970-01-01
      • 1970-01-01
      • 2016-08-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多