给出两个列表,找到前K个产品的有效方法

时间:2018-11-15 10:30:22

标签: python algorithm big-o

给出两个长度相等的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对相乘?

3 个答案:

答案 0 :(得分:3)

如前所述,第一步是对两个列表AB进行降序排序(或仅对两个列表中的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个最大值:

  1. 如果K <<< NK以10s为单位,N以百万为单位)
    在这里,您有几个选择。
  

请注意,由于K <<< N,您可以说O(N*K)几乎是O(N)

  1. K可以与N相同
    • 在这种情况下,最好的选择是使用Merge SortQuick Sort对两个列表进行排序。那就是O(N*lgN)