假设有一个包含 N 个整数的大数组:
const unsigned N = 1e12;
int array[N] = { 1, 3 , 8, -5, 4, 3, -1 -6, 6, ....., N};
应该多次查询不同i
j
indecies范围内的最小元素。返回最小值的复杂度应该小于 O(ji) 并且应该使用少于 O(N^2) 的内存来解决问题。
如何做到这一点?
假设有一个包含 N 个整数的大数组:
const unsigned N = 1e12;
int array[N] = { 1, 3 , 8, -5, 4, 3, -1 -6, 6, ....., N};
应该多次查询不同i
j
indecies范围内的最小元素。返回最小值的复杂度应该小于 O(ji) 并且应该使用少于 O(N^2) 的内存来解决问题。
如何做到这一点?
RMQ 的工作方式如下:
我们保留一个数组 M[N][logN],其中 M[i][j] 显示从 i 开始且长度为 2^j 的最小范围数。为了填充该数组,首先我们计算所有 M[i][0] 值,它们都等于 M[i][0] = A[i](A[i] 是原始数组)。之后,通过归纳,每个 M[i][j] 将等于min(M[i][j - 1], M[i + (1 << (j - 1))][j - 1])即我们通过取其左右部分的最小值来获得更长间隔的值,这应该在上一步中计算,因为我们从最短到最长的间隔。
之后,为了得到[a..b]区间的最小值,你需要找到最大的P,使得2^P不超过区间[a..b]的长度。答案是min(M[a][P], M[b - (1 << P) + 1][P])
正如您所提到的,对于静态数组,最快的解决方案是 O(1) 和 O(n) preproc。但在实践中,您可能希望使用以下方法之一,它也适用于动态数组,并且在我看来更容易理解和编码:
对于那些懂俄语的人,这是解决方案:http ://e-maxx.ru/algo/rmq 对于那些不懂俄语的人,对不起,我没有找到任何东西。如果有人会找到,请编辑我的答案。
一个简单的解决方案是创建一个二维数组,其中条目 [i, j] 存储范围 arr[i..j] 中的最小值。现在可以在 O(1) 时间内计算给定范围的最小值,但预处理需要 O(n^2) 时间。此外,这种方法需要 O(n^2) 额外空间,这对于大型输入数组可能会变得巨大。
另一种解决方案是构建一个Segment树。Segment树可以在适当的时间内进行预处理和查询。对于分段树,预处理时间为 O(n),范围最小查询的时间为 O(Logn)。存储段树所需的额外空间是 O(n)。
段树的表示
Segment树的构建在这里详细解释:
http://www.geeksforgeeks.org/segment-tree-set-1-range-minimum-query/