这是我发现的面试问题。
第一部分是在文件中找到k
最常用的单词。这是一个众所周知的问题,可以在here中找到解决方案。当O(nlogk + k)
是文件大小时,此解决方案的运行时间为n
。
第二部分是在文件中找到k
个最常用的词,但这一次使用并发性。这意味着,如果我们可以在系统中并行运行m
线程-我们如何改善上述解决方案?
这就是我坚持的地方。首先,我想到了将文件拆分为m
个部分,并将每个部分发送到不同的线程,以便他可以进行处理。但是问题在于这些线程将必须共享相同的特里,这意味着它们将必须同步。因此,即使使用这些m
线程可以在纸上获得更好的运行时,实际上,我也很确定使用同步会使运行时比上述实现中的运行时更糟。
您是否有一个想法,如何使用并发来实现这一点,以改善运行时间?
答案 0 :(得分:1)
这是一个map-reduce操作。假设我们有一个长度为N和M线程的文件:
因此,使用M个线程,您可以用O((N / M)* log K +(K + M)* log M)完成整个工作。
如果对第5步使用流式并行合并,则可以将其减少为O((N / M)* log K + K + log M),但这只有在具有 lot < / em>线程。
答案 1 :(得分:0)
如何让每个线程独立地在文件共享中找到最常见的k,然后合并结果?
请注意,我对通过并发读取文件可能带来的任何速度提高表示怀疑,这可能是此问题中最慢的操作。
答案 2 :(得分:0)
您可以使用CountMinSketch
以紧凑的O(1)
形式大致保持计数。这为您提供了沉重的击球手,而没有保留任何文字。假设使用相同的哈希函数,可以将多个草图合并为简单的数组求和。这允许线程并行处理独立的部分。它与哈希表方法类似,不同之处在于您忘记了单词映射。
下一步将是扫描单词词典以确定top k
。如果您为每个线程维护一个词典,则可以将其合并而不是重新扫描文件。对于该列表中的每个项目,您都查询其频率O(1)
,从而可以对它们进行排名以获得最受欢迎。当我们关心频率顺序而不是单词本身时,我们将O(lg k)
减小为O(lg f)
。在这种情况下,具有相同流行度的单词将链接在列表上。如果使用O(1)
或SkipList
,我们可以用MinHeap
中频率最低的单词来评估一个新单词。
然后添加运行时,
O(n/T)
,其中n
是文件大小,T
是线程数O(T * m)
,其中m
是唯一单词(基数)的数量,而T
线程可能会产生所有m
个单词以进行哈希联接O(m * lg f)
,其中f
是最高频率,以查找最受欢迎的单词这将导致O(n/T) + O(T * m) + O(m * lg f)
,其中n
是迄今为止的主要参数,因此实际上它应减少为O(n)
。