【问题标题】:Dynamic algorithm for text auto-correct文本自动更正的动态算法
【发布时间】:2012-04-20 00:53:08
【问题描述】:

我正在编写一个使用levenshtein distance 进行更正的自动更正程序 根据包含 8000 个单词的特定词典,不超过 64 个字符的短语。

字典的每一行都包含一对“Word word_frequency”。 我使用 DictionarEntry 对象来存储这些对。类字典条目有两个字段: value : 存储单词字符串 freq :存储频率 字典存储为 LinkedList。 我从标准输入中读取了 64 个字符的字符串。 在处理它之前,我删除了所有空格。 “凉爽的天气”->“凉爽的天气” 我注意到,在由 levenshtein 动态计算的矩阵的最后一行中,计算每个前缀的 levenshtein 距离(参见维基百科示例) 它返回所有前缀的距离。

函数 lev 返回一个向量,其中包含从第二个参数字符串到第一个参数的所有前缀(包括它自己)的 l.distance。

我的问题是我必须遵守一些额外的规则: 最低标准距离 -> 最小字数 -> 最大频率和 -> 最小词典 这将被解释为好像解决方案的总数大于 1 我们取单词最少的那些。如果还有不止一个,我们遵循规则列表。

我应用的动态类似于背包动态。 不知道怎么实现最小字数规则(最大频数很相似)

这是我迄今为止尝试过的 失败的输入/输出示例: “很矜持” 答案应该是这么矜持的,我得到的其实是这么矜持的 我选择了这种方法,因为它更有效。 Java 的时间限制为 2 秒。

更新:4 月 7 日。我找到了解决我的问题的方法,但是 cpu 时间太大,所以我需要优化它。 它不应高于 2000 毫秒,目前约为 6000 毫秒。所以现在我的主要重点是优化它。

 public static String guess (String input, LinkedList<DictionarEntry> Dictionar){
       String curent = new String();
      String output = new String();

      int costMatrix[][][] = new int [input.length()][8000][input.length()];         
     int index[] = new int[128];
     int prev[]= new int[128];
        int d[]=new int  [128];
        int freq[]= new int[128];
        int wcount[]=new int[128];
        String values[] = new String[128];   
        for (int i=0 ; i < 128 ; i++){
                d[i]=127;
                freq[i]=0;
                wcount[i]=1;
                values[i]="";
        }           
     d[0]=0;
     freq[0]=0;

         for (int i = 0 ; i <input.length(); ++i){  

             curent=input.subSequence(i, input.length()).toString();
             long start =System.currentTimeMillis();
              for (int j = 0 ; j < Dictionar.size();++j){

                  costMatrix[i][j]=lev(Dictionar.get(j).value,curent);
                  for(int k=1;k<costMatrix[i][j].length;++k){

                      if(d[i]+costMatrix[i][j][k]<d[i+k]){
                          d[i+k]= d[i]+costMatrix[i][j][k];
                              values[i+k]=values[i]+Dictionar.get(j).value;
                              freq[i+k]=freq[i]+Dictionar.get(j).freq;
                              index[i+k]=j;
                              prev[i+k]=i;
                              wcount[i+k]=wcount[i]+1;
                      }
                       else if ((d[i]+costMatrix[i][j][k])==d[i+k])
                                        if((wcount[i]+1) <wcount[i+k]){
                              values[i+k]=values[i]+Dictionar.get(j).value;
                              freq[i+k]=freq[i]+Dictionar.get(j).freq;
                              index[i+k]=j;
                              prev[i+k]=i;
                              wcount[i+k]=wcount[i]+1;    
                                        }
                                        else if ((wcount[i]+1)==wcount[i+k])
                                         if((freq[i]+Dictionar.get(j).freq)>freq[i+k]){
                                             values[i+k]=values[i]+Dictionar.get(j).value;
                                             freq[i+k]=freq[i]+Dictionar.get(j).freq;
                                             index[i+k]=j;
                                             prev[i+k]=i;
                                             wcount[i+k]=wcount[i]+1;       
                                         }
                                         else if ((freq[i]+Dictionar.get(j).freq)==freq[i+k]){
                                             if((values[i]+Dictionar.get(j).value).compareTo(values[i+k])>0){
                                                 values[i+k]=values[i]+Dictionar.get(j).value;
                                              freq[i+k]=freq[i]+Dictionar.get(j).freq;
                                              index[i+k]=j;
                                              prev[i+k]=i;
                                              wcount[i+k]=wcount[i]+1;  
                                             }
                                         }
                  }     
              }
              long finished =System.currentTimeMillis();
                    System.out.println((finished-start)); 

      output="";

         } 

          int itr=input.length();
                   while(itr!=0){
      output = Dictionar.get(index[itr]).value + " " + output;
      itr=prev[itr]; 
  } 
     return output;
  }

我应该在哪里实施规则以及如何实施(理想情况下以比使用矩阵更有效的方式)?

如果有任何问题或我留下了不清楚的地方,请随时提问

【问题讨论】:

  • “我得到的东西实际上是这么保留的” [原文如此] 明确一点:你的 8000 个单词的字典有“so”、“re”、“served”和“保留”,但没有“痛”?
  • so reserved 将是正确答案,因为 sore reserved 和 so reserved 之间的 levenshtein 距离相等(如果你忽略空格,我会这样做)但 reserved 频率更高。
  • 必须是动态算法吗?可以使用标准的 java 地图、集合等吗?
  • 是的,它必须是动态算法。是的,我可以使用集合、地图。我想到的直接优化是在我阅读字典项目时创建 costMatrix。在当前代码中,我读取了一个字典项,然后计算它的 levenshtein 以及我所有输入的前缀。很快就会返回一个 cpu 时间的数值。

标签: java dynamic-programming levenshtein-distance autocorrect


【解决方案1】:

您为什么不能使用像 Apache Lucene 这样的现有库?它支持使用Levenshtein距离的fuzzy queries

除此之外,您可能需要考虑Suffix Trees 来加快部分字符串搜索

【讨论】:

  • 我不能使用 Apache Lucene,因为我应该在不使用执行该操作的例程的情况下提供解决方案。例如 Java 有 String.levenshtein。我已经为我的问题添加了修复程序,但现在 cpu 时间太长了。
猜你喜欢
  • 1970-01-01
  • 2012-03-07
  • 1970-01-01
  • 1970-01-01
  • 2014-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多