在此之前,我明确表示这是一项任务,我不希望完整的编码答案。我寻求的只是建议和可能帮助我的代码片段。
所以,我正在读取存储在arrayList中的大约900,000个单词。我需要在java中使用排序数组(或arraylist)计算唯一单词。
到目前为止,我只是循环遍历给定的arrayList并使用
Collections.sort(words);
和Collections.binarySearch(words, wordToLook);
实现如下:
OrderedSet set = new OrderedSet();
for(String a : words){
if(!set.contains(a)){
set.add(a);
}
}
和
public boolean contains(String word) {
Collections.sort(uniqueWords);
int result = Collections.binarySearch(uniqueWords, word);
if(result<0){
return false;
}else{
return true;
}
}
这段代码的运行时间约为60秒,但我想知道是否有更好的方法可以做到这一点,因为每次添加一个元素时运行一个排序看起来非常低效(但如果我使用二进制文件则必须使用搜索)。
非常感谢任何形式的反馈。感谢。
答案 0 :(得分:0)
我不会使用排序数组。我会创建一个Map<String, Integer>
,其中键是你的单词,值是单词出现次数的计数。在阅读每个单词时,请执行以下操作:
Integer count = map.get(word);
if (count == null) {
count = 0;
}
map.put(word, count + 1);
然后只需遍历地图的入口集,并对计数执行任何操作。
如果你知道或者可以估计唯一单词的数量,那么你应该在HashMap构造函数中使用这个数字(所以你不要多次增长地图)。
如果使用排序数组,则运行时间不能比NlogN(其中N是列表中的单词数)成比例。如果使用HashMap,则可以实现与N线性增长的运行时(您自己保存logN的因子)。
使用Map的另一个好处是使用的内存与唯一单词的数量成正比,而不是单词的总数(假设您在阅读单词时构建地图,而不是将所有单词读入集合中然后将它们添加到地图中。)
答案 1 :(得分:0)
因此,您必需使用已排序的数组。没关系,因为你(现在还没有)在现实世界中编程。
我会建议两种选择:
第一个使用二进制搜索(您在当前代码中使用)。
我会创建一个包含两个字段的类:单词(String)和该单词的计数(int)。您将构建这些类的排序数组。
从一个空数组开始,并在读取每个单词时添加到该数组。对于每个单词,请对要构建的数组中的单词执行二进制搜索。搜索将找到包含该单词的条目(并且您将增加计数),或者您将确定该单词尚未在数组中。
当您的二进制搜索结束而没有找到该单词时,您将创建一个新对象来保存单词+ count并将其添加到搜索结束位置的数组中(注意确保您的逻辑真正放置它)在正确的位置保持您的列表排序)。当然,新单词的计数设置为1。
另一种选择:
将所有单词读入列表并对其进行排序。排序后,所有重复项将在列表中彼此相邻。
您将沿着此排序列表向下走,并创建一个单词+计数列表。如果您看到的下一个单词与最后一个单词+ count相同,则递增计数。如果是新单词,请在count = 1的结果列表中添加一个新单词+ count。
答案 2 :(得分:0)
public static int countUnique(array) {
if(array.length == 0) return 0;
int count = 1;
for i from 1 to array.length - 1 {
if(!array[i].equals(array[i - 1])) count++;
}
return count;
}
这是伪代码中的O(N)
算法,用于计算排序数组中唯一条目的数量。它背后的想法是我们计算相等元素组之间的转换数。然后,唯一条目的数量是转换数加1(第一个条目)。
希望您看到在对元素进行排序后如何将此算法应用于数组。
答案 3 :(得分:0)
您总是可以使用比较器来获取唯一值。
List newList = new ArrayList(new Comparator() {
@Override
public int compare(words o1, words o2) {
if(o1.equalsIgnoreCase(o2)){
return 0;
}
return 1;
}
});
现在算了:
单词 - newList = no。重复值。
希望这有助于!!!!