算法 – 在大词序列中找到前K个频率词的最有效的方式

输入:正整数K和大文本。文本实际上可以被视为单词序列。所以我们不必担心如何将它分解成词序。
输出:文本中最常见的K个单词。

我的想法是这样的。

>使用哈希表在遍历整个单词序列时记录所有单词的频率。在这个阶段,键是“字”,值是“字频”。这需要O(n)时间。
>排序(字,字频率)对;并且键是“字频率”。这需要O(n * lg(n))时间与正常排序算法。
>排序后,我们只取前K个字。这需要O(K)时间。

总之,总时间是O(n nlg(n)K)。由于K肯定小于N,所以实际上是O(nlg(n))。

我们可以改善这一点。其实,我们只想要顶尖的K字。其他词语的频率不是我们关心的。所以,我们可以使用“partial Heap sorting”。对于步骤2)和3),我们不只是做排序。相反,我们改变它

2′)建立一个以“word-frequency”为关键字的字(word,word-frequency)对。它需要O(n)时间来构建一个堆;

3′)从堆中提取前K个字。每次提取是O(lg(n))。因此,总时间为O(k * lg(n))。

总之,该解决方案花费时间O(n k * lg(n))。

这只是我的想法。我没有找到方法来改进步骤1)。
我希望一些信息检索专家可以更清楚地说明这个问题。

最佳答案
这可以在O(n)时间内完成

解决方案1:

脚步:

>计数字和哈希它,这将最终在这样的结构

var hash = {
  "I" : 13,
  "like" : 3,
  "meow" : 3,
  "geek" : 3,
  "burger" : 2,
  "cat" : 1,
  "foo" : 100,
  ...
  ...

>遍历散列并找到最常用的字(在本例中为“foo”100),然后创建该大小的数组
>然后我们可以再次遍历散列,并使用单词的出现次数作为数组索引,如果索引中没有什么,创建一个数组else追加它在数组中。然后我们最终得到一个数组,如:

  0   1      2            3                100
[[ ],[ ],[burger],[like, meow, geek],[]...[foo]]

>然后只从最后遍历数组,并收集k个字。

解决方案2:

脚步:

>同上
>使用最小堆并保持最小堆的大小为k,并且对于散列中的每个单词,我们比较单词的出现次数与min,1)如果它大于min值,删除min(如果大小min堆等于k)并在最小堆中插入数字。 2)休息简单条件。
>遍历数组后,我们只需将最小堆转换为数组,并返回数组。

转载注明原文:算法 – 在大词序列中找到前K个频率词的最有效的方式 - 代码日志