build a map<word, count>
build a tokenizer that gives you a word per iteration
for each word*,
if word in map, increment its count
otherwise add with count = 1
sort words by count
for each of the first 50 words,
output word, frequency = count / total_words
# 1 楼答案
你最好的选择是O(n)算法,我会选择一个文本阅读器,它会拆分单词,然后将其添加到一个有序的树中,你会按出现的数量排序,并将它们链接到一个单词。之后,只需进行50次迭代遍历即可获得最高值
# 2 楼答案
O(n)
当然,这些步骤中的一些可能是同时完成的,也可能是不必要的,具体取决于您将使用的数据结构
# 3 楼答案
最有效的可能是使用链接到max-heap的Patricia trie。每次你读一个单词时,把它放在trie上,转到heap和
increase-key
。如果它不在trie中,那么add
选择它并在堆中适当地设置它的密钥用一个Fibonacci heap,
increase-key
就是O(1)
一个不太合理的解决方案是使用
Map<String, Integer>
,每次遇到一个单词时都添加计数,然后根据计数对其entrySet()
进行自定义排序,以获得前50名如果
O(N log N)
排序不可接受,请使用selection algorithm在O(N)
中查找前50名哪种技巧更好实际上取决于你的要求(也就是说,评论这是否更像是一个
[algorithm]
问题,而不是一个[java]
问题很能说明问题)紧跟着选择算法的
Map<String, Integer>
是最实用的,但Patricia trie解决方案显然仅在空间效率方面就优于它(因为公共前缀不会被冗余存储)# 4 楼答案
以下伪代码应该可以做到这一点:
这本质上是O(N),也是jpabluz所建议的。然而,如果你打算在任何类型的“野生”文本中使用它,你会注意到大量垃圾:大写/小写、标点符号、URL、停止词,例如“the”或“and”,计数非常高,同一个单词的多个变体。。。正确的方法是将所有单词小写,删除所有标点符号(以及URL等内容),并在上述伪代码中用星号标记的点添加停止词删除和词干生成