我有一个非常大的字符串数组(大约32k字),我想以有效的方式检查整个数组的相似性。我希望它以百分比的形式返回。我也不知道阵列中有多少个点。我不知道最有效的方法是什么。我目前的想法是检查数组中每两个单词之间的相似性,然后平均该相似性。我希望找到一个更有效的解决方案。 这是我到目前为止所尝试的:
import java.util.*;
import org.apache.commons.lang3.StringUtils;
public class Trial2 {
public static void main(String[] args) {
ArrayList<Double> averageValues = new ArrayList<>();
ArrayList<String> temp = new ArrayList<>(); //holds all the words in the list
for(int i = 0; i < temp.size() - 1; i++) {
double k = StringUtils.getLevenshteinDistance(temp.get(i), temp.get(i + 1));
averageValues.add(k/(double)temp.get(i).length())
}
double average;
for(int i = 0; i < averageValues.size(); i++) {
average += averageValues.get(i);
}
average = average/averageValues.size();
}
}
假设我的临时列表已满。这段代码的问题是它已经嵌入了2个forloops,我不想命中n ^ 3。有没有其他方法可以解决这个问题
请帮忙。
答案 0 :(得分:0)
对于以下内容,我们假设各个条目(例如单词)的长度不会增加。
您的算法只是数组中条目数的O(n),因为它只将每个条目与下一个条目(而不是每个其他条目)进行比较。权衡是它(仅)提供总相似性的启发式估计。好:您的算法访问每个条目,因此每个条目对启发式结果至少有一些影响(但请参阅下面的统计信息)。
建议:
为避免增长成本,您可以给averageValues一个初始大小等于temp的初始大小(如果需要,则为-1)。但如果您执行以下操作,则甚至不需要这样做。
你可以通过让第一个循环只是累积结果来消除第二个循环:
sumOfDifferences += k/(double)temp.get(i).length();
然后循环:
average = sumOfDifferences/temp.size();
这可能会运行得更快,因为在您的版本中,如果另一个线程/进程在此时运行,则第二个循环运行时,条目在缓存中不再存在。 这也允许你删除averageValues ArrayList,因此不再需要增长成本。
不是优化而只是考虑:考虑是否按照(double)temp.get(i).length()
划分你想要实现的目标。
从统计数据来看,你总是要比较下一个条目,这可能很麻烦。例如。如果单词被排序,将会有很大的偏见。想想首先随机化阵列是否会更好。