我有 n 排序列表(5< n< 300)。这些列表很长(300000+元组)。选择单个列表的前k个当然是微不足道的 - 它们就在列表的头部。
k = 2的例子:
top2 (L1: [ 'a': 10, 'b': 4, 'c':3 ]) = ['a':10 'b':4]
top2 (L2: [ 'c': 5, 'b': 2, 'a':0 ]) = ['c':5 'b':2]
当我想要在所有排序列表中组合top k 时,它变得更有趣。
top2(L1+L2) = ['a':10, 'c':8]
仅仅组合单个列表的前k个不一定会得到正确的结果:
top2(top2(L1)+top2(L2)) = ['a':10, 'b':6]
目标是减少所需的空间,并使排序的列表保持较小。
top2(topX(L1)+topX(L2)) = ['a':10, 'c':8]
问题在于是否存在一种算法来计算具有正确顺序的组合顶部k,同时切断某个位置处的列表的长尾。如果有:如何找到限制X哪里可以安全切割?
注意:正确的计数并不重要。只有订单。
top2(magic([L1,L2])) = ['a', 'c']
答案 0 :(得分:1)
如果我正确理解你的问题,正确的输出是前10项,无论每个项目的列表如何。如果这是正确的,那么从每个列表中的前10个项开始将允许您生成正确的输出(如果您只想要输出中的唯一项,但输入可能包含重复项,那么每个列表中需要10个唯一项)
在最极端的情况下,所有顶级项目都来自一个列表,其他列表中的所有项目都将被忽略。在这种情况下,在一个列表中包含10个项目就足以产生正确的结果。
答案 1 :(得分:1)
此算法使用O(U)内存,其中U是唯一键的数量。我怀疑是否可以实现较低的内存界限,因为无法确定哪些键可以被丢弃直到所有钥匙已被总结。
答案 2 :(得分:0)
您没有指定您拥有的列表数量。如果n很小,那么步骤4可以非常简单地完成(只需重新排序列表)。随着n的增长,你可能想要考虑更有效的方法来求助和几乎排序的列表列表。
答案 3 :(得分:0)
我不明白两个列表中是否出现'a',他们的计数必须合并。这是一种新的内存有效算法:
(新)算法:
分析:此算法只能使用O(k)附加内存来实现,以存储最小堆。它需要做出一些权衡来实现这一目标:
注意:此算法假设可以快速比较ID。字符串比较并非无足轻重。我建议将字符串ID散列为整数。它们不必是唯一的哈希值,但必须检查冲突,以便正确排序/比较所有ID。当然,这会增加内存/时间的复杂性。
答案 4 :(得分:0)
完美的解决方案要求至少检查一次所有元组。
但是,可以在不检查每个元组的情况下将关闭转换为完美的解决方案。丢弃“长尾”会引入误差。您可以使用某种类型的启发式来计算误差范围何时可以接受。
例如,如果有n = 100个已排序的列表,并且您已经检查了每个列表,直到计数为2,那么密钥的总计数最多可以增加200个。
我建议采用迭代方法:
该算法假设前k个键的计数将接近某个值,进一步的长尾被遍历。您可以使用其他启发式而不是特定百分比,例如前k中新键的数量,前k键被洗牌多少等等...
答案 5 :(得分:0)
通过mapreduce实现这一目标有一个明智的方法:
http://www.yourdailygeekery.com/2011/05/16/top-k-with-mapreduce.html
答案 6 :(得分:-1)
总的来说,我认为你遇到了麻烦。想象一下以下列表:
['a':100, 'b':99, ...]
['c':90, 'd':89, ..., 'b':2]
你有k = 1(即你只想要前一个)。 'b'是正确的答案,但你需要一直看到第二个列表的末尾才能意识到'b'击败了'a'。
编辑:
如果你有正确的分布(长,低计数尾),你可能会做得更好。现在让我们保持k = 1,让我们的生活更轻松。
基本算法是保留您到目前为止看到的键及其相关总计的哈希映射。向下走列表处理元素并更新地图。
关键的观察结果是,一个密钥最多可以计入每个列表当前处理点的计数总和(称为和S)。因此,在每个步骤中,您可以从哈希映射中删除总数超过当前最大计数元素的S的任何键。 (我不确定你需要修剪什么数据结构,因为你需要在给定一系列计数的情况下查找密钥 - 可能是优先级队列?)
当您的哈希映射中只有一个元素,并且其计数至少为S时,您可以停止处理列表并将该元素作为答案返回。如果你的计数分布很好,这个提前退出可能实际上触发,所以你不必处理所有列表。