快速找到大数字矩阵中的第n大产品

时间:2012-05-17 13:50:57

标签: performance algorithm search sorting language-agnostic

我正在研究一种可以处理大量项目的排序/排名算法,我需要以有效的方式实现以下算法才能使其工作:


有两个数字列表。它们同样长,约100-500万件。从这里我需要找到这些列表之间的第n大产品,即。如果您创建一个矩阵,其中您有一个列表,那么您有另一个列表,每个单元格是上面的数字和侧面的数字的乘积。

示例:列表为A=[1, 3, 4]B=[2, 2, 5]。然后产品是[2, 2, 5, 6, 6, 15, 8, 8, 20]。如果我想要第三大,那就是8。

天真的解决方案是简单地生成这些数字,对它们进行排序,然后选择第n个最大数字。但那是O(m^2 * log m^2),其中m是小列表中元素的数量,而且速度不够快。

我认为我需要的是先对两个小清单进行排序。那是O(m * log m)。然后我肯定知道最大的一个A [0] * B [0]。第二大的是A [0] * B [1]或A [1] * B [0],......

我觉得这可以在O(f(n))步骤中完成,与矩阵的大小无关。但我无法找到一种有效的方法来完成这一部分。


编辑:有一个被删除的答案,建议记住两个有序集中的位置,然后看A [a] * B [b + 1]和A [a + 1] * B [b] ,返回较大的一个并递增a / b。我要在删除之前发表这条评论:

  

这不起作用。想象一下两个列表A = B = [3,2,1]。这会给你   像[9,6,3; 6,4,2; 3,2,1]。所以你从(0,0)= 9开始,转到   (0,1)= 6然后选择是(0,2)= 3或(1,1)= 4。但是,这会   错过(1,0)= 6,这比两者都大。所以你不能只看   两个邻居,但你必须回溯。

3 个答案:

答案 0 :(得分:4)

我认为可以在O(n log n + n log m)中完成。这是我的算法草图,我认为将起作用。这有点粗糙。

  1. 按降序排序。 (需O(m log m)
  2. 排序B降序。 (需O(m log m)
  3. smin(m, n)。 (需O(1)
  4. 通过s创建L[0]延迟序列迭代器L[s-1]L[i]将遍历sA[i]*B[0]A[i]*B[1],...,A[i]*B[s-1]。 (需O(s)
  5. 将迭代器放在优先级队列q中。迭代器将根据其当前值进行优先级排序。 (需要O(s),因为最初他们已经有序了)
  6. n中提取q个值。拉出的最后一个值将是所需的结果。拉动迭代器时,会使用其下一个值作为新优先级将其重新插入q。如果迭代器已用完,请勿重新插入。 (需O(n log s)
  7. 总之,此算法将采用O(m log m + (s + n)log s),但s等于mn

答案 1 :(得分:0)

您不需要对500 000个元素进行排序以获得前3个。

只需取第3个,将它们放入SortedList,然后遍历列表,用新值替换3个元素中的最小值,如果更高,则求结果列表。

对两个列表执行此操作,您将以3 * 3矩阵结束,其中应该很容易取第3个值。

Here is an implementation in scala

如果我们假设n小于m,且A = [1,3,4]且B = [2,2,5],则n = 2:

你会采取(3,4)=>他们排序(4​​,3)
然后取(2,5)=>对它们进行排序(5,2)

您现在可以进行压缩搜索。当然,现在最大的产品是(5,4)。但下一个是(4 * 2)或(5 * 3)。对于更长的列表,您可以记住4 * 2的结果是什么,仅将其与下一个产品进行比较,采用另一种方式。这样你只会计算一个产品太多。

答案 2 :(得分:0)

我认为没有O(f(n))的算法,它与m无关。

但是有一个相对较快的O(n * logm)算法:

首先,我们对两个数组进行排序,得到A [0]> A [1]> ...> A [m-1]和B [0]> B [1]> ...> B [M-1]。 (当然,这是O(mlogm)。)

然后我们构建一个最大堆,其元素是A [0] * B [0],A [0] * B [1],... A [0] * B [m-1]。我们维持一个“指针数组”P [0],P [1],... P [m-1]。 P [i] = x表示B [i] * A [x]当前在堆中。所有P [i]最初都为零。

在每次迭代中,我们从堆中弹出max元素,这是下一个最大的产品。假设它来自B [i] * A [P [i]](我们可以记录堆中的元素来自哪个B [i]),然后我们将相应的指针向前移动:P [i] + = 1,并将新的B [i] * A [P [i]]推入堆中。 (如果P [i]移动到超出范围(> = m),我们只需将-inf推入堆中。)

在第n次迭代之后,我们获得了第n个最大的产品。

有n次迭代,每次都是O(logm)。

编辑:添加一些细节