Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 快速在大型数字矩阵中找到第n个最大乘积_Performance_Algorithm_Search_Sorting_Language Agnostic - Fatal编程技术网

Performance 快速在大型数字矩阵中找到第n个最大乘积

Performance 快速在大型数字矩阵中找到第n个最大乘积,performance,algorithm,search,sorting,language-agnostic,Performance,Algorithm,Search,Sorting,Language Agnostic,我正在研究一种能够处理大量项目的排序/排名算法,我需要以有效的方式实现以下算法: 有两个数字列表。它们同样长,大约有10-50万件。从这里我需要找到这些列表之间的第n个最大乘积,也就是说,如果你创建一个矩阵,上面有一个列表,边上有另一个列表,每个单元格是上面的数字和边上的数字的乘积 示例:列表是A=[1,3,4]和B=[2,2,5]。然后产品是[2,2,5,6,6,15,8,8,20]。如果我想要第三大的,那就是8 简单的解决方案是生成这些数字,对它们进行排序,然后选择第n个最大的数字。但是这

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


有两个数字列表。它们同样长,大约有10-50万件。从这里我需要找到这些列表之间的第n个最大乘积,也就是说,如果你创建一个矩阵,上面有一个列表,边上有另一个列表,每个单元格是上面的数字和边上的数字的乘积

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

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

我想我需要的是首先对这两个小列表进行排序。即
O(m*logm)
。然后我确定最大的一个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,后者比两者都大。所以你不能只看 两个邻居,但你必须回溯


您不需要对500000个元素进行排序就可以得到前3个元素

只需取前3个元素,将它们放入SortedList中,并在列表上迭代,用新值替换3个元素中最小的元素(如果值更高),然后使用生成的列表

对两个列表都这样做,您将以一个3*3矩阵结束,在这个矩阵中,取第三个值应该很容易

如果我们假设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的结果是什么,只将其与下一个产品进行比较,反之亦然。这样你只会计算一个产品太多

我认为没有一个独立于m的O(f(n))算法

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

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

然后我们构建一个max堆,其元素是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)


编辑:添加一些细节

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

  • 按降序排序。(取
    O(m log m)
  • 按降序排序。(取
    O(m log m)
  • s
    be
    min(m,n)
    。(取
    O(1)
  • 通过
    L[s-1]
    创建
    s
    惰性序列迭代器
    L[0]
    L[i]
    将迭代
    s
    A[i]*B[0]
    A[i]*B[1]
    ,…,
    A[i]*B[s-1]
    。(采取
    O(s)
  • 将迭代器放入优先级队列
    q
    。迭代器将根据其当前值进行优先级排序。(采取
    O(s)
    ,因为最初它们已按顺序排列)
  • q
    中提取
    n
    值。最后提取的值将是所需的结果。当抽取迭代器时,它将使用其下一个值作为新的优先级重新插入
    q
    。如果迭代器已耗尽,请不要重新插入它。(取
    O(n个日志)

  • 总之,这个算法将采用
    O(m log m+(s+n)log s)
    ,但是
    s
    等于
    m
    n

    n有界于范围(0..m^2),所以我认为你不能断言任何O(f(n))与矩阵的大小无关。生成的矩阵称为两个向量之间的外积。列表值的范围是什么?如果在实践中,范围比列表的大小小得多,那么作为范围大小函数的算法可能比作为列表大小函数的算法更好。请看第k个和的类似问题:a和B的样本都已排序。我们应该假设它们总是被分类的吗?但我并不总是需要第三个。它可以是从1到m^2的任意值。如果是在下半场,我可以反转排序,找到第(m^2-n)个最小的。所以最坏的情况是得到(250000)^2元素,这是一个很大的数目