算法:从n个数组(队列)

时间:2016-01-11 05:36:30

标签: algorithm

假设有n个正数队列。我需要从这些队列中选择最少的k个数字。请注意,这些是队列,因此排序很重要,一次只能从任何队列中选择第一个数字。一旦选择了该号码并从队列中删除,我们就可以继续进入该队列中的下一个号码。因此不允许排序(顺序很重要)。

例如:

找到两个数字的最小总和

2 12 3 4 
8 2 2
10 10

在上面的示例中,我可以从第一个队列中选择2,从第二个队列中选择8个,从第二个队列中选择8和2。两种选择都给出了总和10.

示例2:

找到两个数字的最小总和

4 15 2
8 2 2
10 10

在上面的示例中,必须从第二个列表中选择8和2。

我第一次考虑合并K排序列表的行,但它没有工作。我只能想到一种有效的方法。它是尝试所有队列中的所有组合。 有人可以建议更好的方式或指导我吗?

2 个答案:

答案 0 :(得分:13)

F(qs, k)成为从队列qs中选择k个数字的最小总和。然后:

F([], k) = 0 if k == 0, otherwise +infinity.
F([q] + qs, k) = min_i(q[0] + q[1] + ... + q[i-1] + F(qs, k-i) for i in 0...k)

也就是说,如果您没有剩余队列,则最小总和为0,否则,您可以从第一个队列中获取i个数字,从其余部分中获取k-i

这可以通过构建(n,k)表来有效地使用动态编程来解决,其中n是队列的数量。在Python 2中:

def F(qs, n, k, cache):
    if k == 0:
        return 0
    if n == 0:
        return 1e12
    if (n, k) not in cache:
        best = 1e12
        s = 0
        for i in xrange(k+1):
            if i > len(qs[len(qs)-n]):
                break
            if i > 0:
                s += qs[len(qs)-n][i-1]
            best = min(best, s + F(qs, n-1, k-i, cache))
        cache[n, k] = best
    return cache[n, k]

egs = [
    (2, [[2, 2, 3, 4], [8, 2, 2], [10, 10]]),
    (2, [[4, 15, 2], [8, 2, 2], [10, 10]]),
    (3, [[100, 100, 100], [101, 101, 2]])
]

for k, qs in egs:
    print k, qs
    print F(qs, len(qs), k, dict())
    print

打印

2 [[2, 2, 3, 4], [8, 2, 2], [10, 10]]
4

2 [[4, 15, 2], [8, 2, 2], [10, 10]]
10

3 [[100, 100, 100], [101, 101, 2]]
204

答案 1 :(得分:0)

首先尝试解决一个更简单的问题:如何从数组长度m?

中找到最小的k个元素

从数组的前k个元素初始化最大堆大小k(是max-heap而不是min-heap)。循环遍历阵列的其余部分。在每个步骤中,将当前元素与堆的根进行比较(这是到目前为止看到的第k个最小元素)。如果当前元素较小,则删除堆根并插入当前元素,小心保持堆不变。

完成后,堆包含数组中最小的k个元素。该算法具有时间复杂度O(m log k)和空间复杂度O(k)

在Python中实现。 Python只有min-heap module,因此通过消除所有内容的负面来模拟最大堆。

import heapq # min-heap operations 

def sum_smallest_k(queues, k):
    """Sum the smallest k elements across queues"""
    heap = [] # maintain a max-heap size k

    for queue in queues:
        for x in queue:
            if len(heap) < k:
                heapq.heappush(heap, -1 * x)
            else:
                heapq.heappushpop(heap, -1 * x)

    return -1 * sum(heap)

您的示例

>>> sum_smallest_k([[2, 12, 3, 4], [8, 2, 2], [10, 10]], 2)
4
>>> sum_smallest_k([[4, 15, 2], [8, 2, 2], [10, 10]], 2)
4