找到最小长度,使滑动窗口按其全长滑动包含给定集合的所有间隔

时间:2016-02-28 18:53:18

标签: algorithm

我需要按价格实施产品的分面搜索,即我希望有效地生成一系列范围,其中包含每个范围内的产品数量。

出于各种原因,我可以建立的最好的东西是一个表格,每个产品都给出了产品的最小和最大可能价格,例如:

idProduct | priceMin | priceMax
1         | 15       | 20
2         | 2        | 3
3         | 5        | 7
4         | 13       | 19

我们可以假设所有数字都是自然整数。

为了提高查询效率,我希望找到一个s大小,以确保每个产品都有一个自然数k,例如:

k * s <= priceMin && priceMax <= (k + 1) * s

换句话说,预先计算范围列表,以便很容易确定给定产品是否属于其中一个范围。

使用上面的数据,数字12是s的合适值,因为:

1 * 12 <= 15 && 20 <= 2 * 12
0 * 12 <= 2 && 3 <= 1 * 12
0 * 12 <= 5 && 7 <= 1 * 12
1 * 12 <= 13 && 19 <= 2 * 12

但是,数字6不是s的合适值,因为它不适用于产品#3 0 * 6 <= 57 > 1 * 6

在现实世界中,价格表将有数十万行,因此我正在寻找一种有效的算法,可以让我找到s的最小可能值。

如果这是一个经典问题并且您知道它的名字,我可以从那里谷歌,但到目前为止我还无法找到任何相关内容。

1 个答案:

答案 0 :(得分:1)

这是一个相当有效的算法(O(n + P log P),其中P是最大价格,假设整数价格)。 (我担心你的约束对你的喜好来说太大了,但是呃。)

观察(如Jan Dvorak先做的那样)条件

there exists k such that k * s <= priceMin and priceMax <= (k + 1) * s

相当于

for all k, it holds that k * s <= priceMin or priceMax <= k * s

相当于

for all k, it does not hold that priceMin < k * s < priceMax.

证据不错,但我不打算把它写出来。

该算法的第一步是计算开放价格区间(priceMin, priceMax)作为位图的并集。

deltaIntervalCount = [0] * (P + 1)
for priceMin, priceMax in priceIntervals:
    deltaIntervalCount[priceMin + 1] += 1
    deltaIntervalCount[priceMax] -= 1
intervalCount = [0] * (P + 1)
for p in range(1, P + 1):
    intervalCount[p] = intervalCount[p - 1] + deltaIntervalCount[p]
forbidden = [intervalCount[p] > 0 for p in range(P + 1)]

该算法的第二步是按顺序尝试s的候选者。

for s in range(1, P + 1):
    if all(not forbidden[k * s] for k in range(P // s + 1)):
        return s