【问题标题】:A more efficient way of finding English words that are one letter off from eachother一种更有效的方法来查找彼此相隔一个字母的英语单词
【发布时间】:2012-11-10 18:23:47
【问题描述】:

我写了一个小程序,试图找到两个长度相等的英语单词之间的联系。单词 A 将通过一次更改一个字母转换为单词 B,每个新创建的单词必须是一个英文单词。

例如:

Word A = BANG
Word B = DUST

结果:

BANG -> BUNG ->BUNT -> DUNT -> DUST

我的过程:

  1. 将英文单词表(由 109582 个单词组成)加载到 Map<Integer, List<String>> _wordMap = new HashMap(); 中,键是单词长度。

  2. 用户输入 2 个字。

  3. createGraph 创建图表。

  4. 计算这两个节点之间的最短路径

  5. 打印出结果。

一切正常,但我对第 3 步所花费的时间不满意。

见:

Completely loaded 109582 words!
CreateMap took: 30 milsecs
CreateGraph took: 17417 milsecs
(HOISE : HORSE)
(HOISE : POISE)
(POISE : PRISE)
(ARISE : PRISE)
(ANISE : ARISE)
(ANILE : ANISE)
(ANILE : ANKLE)
The wholething took: 17866 milsecs

我对在第 3 步中创建图表所花费的时间不满意,这是我的代码(我使用 JgraphT 制作图表):

private List<String> _wordList = new ArrayList();  // list of all 109582 English words
private Map<Integer, List<String>> _wordMap = new HashMap();  // Map grouping all the words by their length()
private UndirectedGraph<String, DefaultEdge> _wordGraph =
        new SimpleGraph<String, DefaultEdge>(DefaultEdge.class);  // Graph used to calculate the shortest path from one node to the other.


private void createGraph(int wordLength){

    long before = System.currentTimeMillis();
    List<String> words = _wordMap.get(wordLength);
    for(String word:words){
        _wordGraph.addVertex(word);  // adds a node
        for(String wordToTest : _wordList){
            if (isSimilar(word, wordToTest)) {        
                _wordGraph.addVertex(wordToTest);  // adds another node
                _wordGraph.addEdge(word, wordToTest);  // connecting 2 nodes if they are one letter off from eachother
            }
        }            
    }        

    System.out.println("CreateGraph took: " + (System.currentTimeMillis() - before)+ " milsecs");
}


private boolean isSimilar(String wordA, String wordB) {
    if(wordA.length() != wordB.length()){
        return false;
    }        

    int matchingLetters = 0;
    if (wordA.equalsIgnoreCase(wordB)) {
        return false;
    }
    for (int i = 0; i < wordA.length(); i++) {

        if (wordA.charAt(i) == wordB.charAt(i)) {
            matchingLetters++;
        }
    }
    if (matchingLetters == wordA.length() - 1) {
        return true;
    }
    return false;
}

我的问题:

如何改进我的算法以加快处理速度?

对于正在阅读本文的任何 redditor,是的,我是在昨天看到 /r/askreddit 的帖子后创建的。

【问题讨论】:

  • 有什么理由不使用 Levenshtein 距离? en.wikipedia.org/wiki/Levenshtein_distance
  • 您是否只是想找到从单词 A 创建单词 B 的最少转换次数? Word A 和 Word B 是输入参数吗(即提前知道)?在这种情况下,您应该使用上面提到的 Levenshtein 距离。但是,听起来您一次要翻译一个字母,并且每个中间词也必须是英文单词?然而,如果这是真的,考虑到你的“BANG -> BUNG ->BUNT -> DUNT -> DUST”的例子...... BUNG 和 BUNT 真的是英文单词吗?或者.. 只有字 A 是输入参数,字 B 是转换的结果?好困惑……
  • @GreenieMeanie 如果您不熟悉这两个单词,您可以在字典中查找它们,这两个是实际的英语单词。并且使用 Levenshtein 距离与我的问题无关,我的程序的瓶颈是从文本文件中提取所有数据,然后将所有数据连接到一个图表中,Jon 已经帮助我解决了,如何计算最短路径不是我的问题的一部分(我自己解决这部分没有问题)。我只问如何打破瓶颈,如果你在我最初的问题中不清楚,这就是我的意思。
  • 最初的问题根本不清楚,这就是为什么另一个人的第一条评论问你为什么不使用 Levenshtein 距离。另外,我认为大多数人都不知道,甚至会开始假设 BUNG、BUNT 或 DUNT 是真实的词,所以这会导致另一个混淆点。

标签: java algorithm


【解决方案1】:

这是一个初步的想法:

创建一个Map&lt;String, List&lt;String&gt;&gt;(如果您使用 Guava,则创建一个 Multimap&lt;String, String&gt;),对于每个单词,一次“删除”一个字母,然后将原始单词添加到该已删除单词的列表中.所以你最终会得到:

.ORSE => NORSE, HORSE, GORSE (etc)
H.RSE => HORSE
HO.SE => HORSE, HOUSE (etc)

此时,给定一个单词,您可以非常轻松地找到与其相似的所有单词 - 只需再次执行相同的过程,但无需添加到地图中,只需获取每个“空白”的所有值版本。

【讨论】:

  • 哦,这很有趣,我没想到,让我试试,谢谢。
  • 这太不可思议了!前17866毫秒,后2381毫秒,你是神。
【解决方案2】:

您可能需要通过分析器运行它以查看大部分时间都花在了哪里,尤其是因为您正在使用库类 - 否则您可能会付出很多努力但看不到明显的改进。

您可以在开始之前将所有单词小写,以避免每次比较时都出现equalsIgnoreCase()。事实上,这是您的代码中的一个不一致之处 - 您最初使用 equalsIgnoreCase(),但随后以区分大小写的方式比较字符:if (wordA.charAt(i) == wordB.charAt(i))。完全消除 equalsIgnoreCase() 检查可能是值得的,因为这与下面的 charAt 循环基本相同。

您可以更改比较循环,使其在找到多个不同字母时提前结束,而不是比较所有字母,然后才检查有多少匹配或不同。

(更新:这个答案是关于优化您当前的代码。我意识到,再次阅读您的问题,您可能会询问替代算法!)

【讨论】:

    【解决方案3】:

    您可以对相同长度的单词列表进行排序,然后进行for (int i = 0; i &lt; n; ++i) for (int j = i + 1; j &lt; n; ++j) { } 类型的循环嵌套。

    在 isSimilar 中计算差异并在 2 上返回 false。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-03
      • 2011-05-13
      • 1970-01-01
      • 2021-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多