这显然是一个面试问题(在面试问题的集合中找到),但即使它不是很酷。
我们被告知要在所有复杂性措施上有效地做到这一点。我想创建一个HashMap,将单词映射到它们的频率。这将是时间和空间复杂度的O(n),但由于可能有很多单词,我们不能假设我们可以将所有内容存储在内存中。
我必须补充一点,问题中没有任何内容说这些词不能存储在内存中,但是如果是这样的话怎么办?如果情况并非如此,那么这个问题似乎并不具有挑战性。
答案 0 :(得分:19)
优化我自己的时间:
sort file | uniq -c | sort -nr | head -10
可能后跟awk '{print $2}'
以消除计数。
答案 1 :(得分:12)
我认为trie data structure是一种选择。
在trie中,您可以在每个节点中记录字数,表示从根到当前节点的路径上由字符组成的字的频率。
设置trie的时间复杂度是O(Ln)~O(n)(其中L是最长单词中的字符数,我们可以将其视为常数)。为了找到前10个单词,我们可以遍历trie,这也需要花费O(n)。所以需要O(n)来解决这个问题。
答案 2 :(得分:3)
完整的解决方案是这样的:
使用Trie,成本将为O(k * N),因为总词数通常大于词汇量的大小。最后,由于大多数西方语言的k值较小,因此可以假设线性复杂度。
答案 3 :(得分:2)
我在C#中做过这样的(样本)
int wordFrequency = 10;
string words = "hello how r u u u u u u u u u u u u u u u u u u ? hello there u u u u ! great to c u there. hello .hello hello hello hello hello .hello hello hello hello hello hello ";
var result = (from word in words.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries)
group word by word into g
select new { Word = g.Key, Occurance = g.Count() }).ToList().FindAll(i => i.Occurance >= wordFrequency);
答案 4 :(得分:2)
假设我们为26个字母表中的每一个分配一个随机素数。然后我们扫描文件。每当我们找到一个单词时,我们就会计算它的哈希值(基于位置的公式和制作单词的字母表的值)。如果我们在哈希表中找到这个值,那么我们肯定知道我们没有第一次遇到它并且我们增加它的键值。并维护一个最大为10的数组。但是如果我们遇到一个新的哈希,那么我们存储该哈希值的文件指针,并将该键初始化为0.。
答案 5 :(得分:1)
您可以进行时间/空间权衡并通过O(n^2)
获取时间和O(1)
(内存)空间,方法是计算每次在线性传递中每次出现单词时出现的次数。数据。如果计数在目前为止发现的前10名之上,那么保留单词和计数,否则忽略它。
答案 6 :(得分:1)
说构建哈希并对值进行排序是最好的。我倾向于同意。 http://www.allinterview.com/showanswers/56657.html
这是一个类似的Bash实现......我想 http://www.commandlinefu.com/commands/view/5994/computes-the-most-frequent-used-words-of-a-text-file
答案 7 :(得分:1)
根据输入数据的大小,保留HashMap可能是也可能不是一个好主意。比如说,我们的哈希映射太大而无法放入主内存。这可能导致大量内存传输,因为大多数哈希映射实现需要随机访问,并且在缓存上不会很好。
在这种情况下,对输入数据进行排序将是更好的解决方案。
答案 8 :(得分:1)
我认为这是计数排序的典型应用,因为每个单词的出现总和等于单词的总数。具有计数排序的哈希表应该在与单词数量成比例的时间内完成工作。
答案 9 :(得分:0)
循环显示单词串并将每个单词存储在字典中(使用python)以及它们作为值出现的次数。
答案 10 :(得分:0)
如果单词列表不适合内存,则可以将文件拆分为止。生成每个部分的直方图(顺序或并行),并合并结果(如果您希望保证所有输入的正确性,但不应该损害O(n)工作量,或者不应该损害O(n)工作,其结果可能有点繁琐。 k任务的O(n / k)时间。)
答案 11 :(得分:0)
Radix tree或其中一个变体通常会允许您通过折叠常用序列来节省存储空间。
构建它将需要O(nk) - 其中k是“集合中所有字符串的最大长度”。
答案 12 :(得分:0)
第1步:如果文件非常大且无法在内存中进行排序,则可以将其拆分为可在内存中排序的块。
第2步:对于每个已排序的块计算排序对(单词,nr_occurrence),在他的位置,您可以放弃到块,因为您只需要排序的对。
第3步:对块进行迭代并对块进行排序,并始终保持前十位。
示例:
第1步:
a b ab ab ab b b c c ab ab
分成:
块1:a b a ab
块2:abb a a b b
块3:c c ab ab
第2步:
块1:a2,b1,ab1
块2:a2,b2,abb1
块3:c2,ab2
第3步(合并块并保持前十名):
a4 b3 ab3 c2 abb1
答案 13 :(得分:0)
int k = 0;
int n = i;
int j;
string[] stringList = h.Split(" ".ToCharArray(),
StringSplitOptions.RemoveEmptyEntries);
int m = stringList.Count();
for (j = 0; j < m; j++)
{
int c = 0;
for (k = 0; k < m; k++)
{
if (string.Compare(stringList[j], stringList[k]) == 0)
{
c = c + 1;
}
}
}
答案 14 :(得分:0)
不是最有效的CPU,而且是UGLY,但只花了2分钟才敲出来:
perl -lane '$h{$_}++ for @F; END{for $w (sort {$h{$b}<=>$h{$a}} keys %h) {print "$h{$w}\t$w"}}' file | head
使用-n
来循环每一行
使用@F
将每行分成-a
个单词
每个$_
字增加散列%h
到达END
file
后,
频率为sort
哈希值
打印频率$h{$w}
和单词$w
使用bash head
停在10行
使用此网页的文字作为输入:
121 the
77 a
48 in
46 to
44 of
39 at
33 is
30 vote
29 and
25 you
我将这个解决方案与顶级shell解决方案(ben jackson)在一个3.3GB的文本文件上进行了基准测试,其中包含580,000,000个单词。
Perl 5.22在171秒内完成,而shell解决方案在474秒内完成。