给出两个长度相等的N
列表,我想找到最大K
的乘积,通过将每个列表中的一个元素相乘可以得到最大乘积。例如,如果
> A = [7, 9, 4, 1, 6]
> B = [8, 1, 3, 10, 7]
> K = 3
结果是[90, 72, 70]
或[9*10, 9*8, 7*10]
,由
> sorted([x*y for x in A for y in B], reverse=True)[:K]
[90, 72, 70]
是否有一种更高效的算法,不涉及将所有N^2
对相乘?
答案 0 :(得分:3)
如前所述,第一步是对两个列表A
和B
进行降序排序(或仅对两个列表中的K个进行最大排序)。然后,所有最大K乘积将位于左上角的大致三角形区域,最大乘积为A[0]*B[0]
。换句话说,如果A[i]*B[j]
位于前K,则A[i-1]*B[j]
和A[i]*B[j-1]
都必须同时位于(假设i, j > 0
)。
因此,您可以从左上角开始,然后使用Heap扩展当前元素的“下”和“右”邻居,并将它们也放到堆上,直到您拥有所需的所有K元素。或以A的所有K个最大元素与堆中已经存在的B的最大元素配对,然后仅向一个方向扩展。
使用heapq
模块的Python示例,但几乎所有其他语言都可以使用。请注意,我们正在向堆中添加负产品,因为堆将按照最小的优先顺序进行排序。
def top_k_prod(A, B, k):
A = heapq.nlargest(k, A)
B = heapq.nlargest(k, B)
result = []
heap = [(-A[i] * B[0], i, 0) for i in range(len(A))]
while heap and len(result) < k:
p, a, b = heapq.heappop(heap)
result.append(-p)
if b < len(B)-1:
heapq.heappush(heap, (-A[a] * B[b+1], a, b+1))
return result
示例:
import random
A = [random.randint(0, 100) for _ in range(100)]
B = [random.randint(0, 100) for _ in range(100)]
K = 20
result = top_k_prod(A, B, K)
test = sorted([x*y for x in A for y in B], reverse=True)[:K]
print(result)
# [9900, 9702, 9603, 9600, 9504, 9408, 9405, 9405, 9400, 9400, 9312, 9306, 9300, 9216, 9212, 9212, 9207, 9200, 9120, 9120]
print(result == test)
# True
排序O(NlogN + KlogK)
和A
的复杂度应该约为B
,然后使用循环中的堆操作对 about K
进行排序。三角形“目标”区域中的每个单元仅从其左邻居扩展一次,添加到堆中但未使用的单元也限制为K(每个“行”中的一个),最多提供2 * K个元素检查过。
答案 1 :(得分:0)
实际解决方案:
使用partial_sort从列表A中找到最大的K
元素,从列表B中找到最大的K
元素(这是快速排序的众所周知的修改,我确信python具有在其库中相同)。这些新列表构成的最大产品也是原始列表的最大产品。然后使用max-heap(优先级队列)从新列表中找到K
个最大的产品。
答案 2 :(得分:0)
如果我们从两个列表中都找到K个max值,则两个列表中都将有最大K
个乘积。
我建议两种方法来找出K个最大值:
K <<< N
(K
以10s为单位,N
以百万为单位)O(N*K)
K
个最大值。即使是O(N*K)
请注意,由于
K <<< N
,您可以说O(N*K)
几乎是O(N)
K
可以与N
相同
O(N*lgN)