假设有一个包含N个整数的大数组:
const unsigned N = 1e12;
int array[N] = { 1, 3 , 8, -5, 4, 3, -1 -6, 6, ....., N};
应该多次查询不同i
j
点范围内的最小元素。返回最小值的复杂度应小于O(j-i),并且应使用小于O(N ^ 2)的内存来解决问题。
如何做到这一点?
答案 0 :(得分:3)
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 <&lt;(j-1))] [ j - 1])即我们通过将其左边和右边的最小值取得更长的间隔来获得值。正确的部分,应该在前一步计算,因为我们从最短到最长的间隔。
之后,要获得[a..b]间隔中的最小值,您需要找到最大的P,这样2 ^ P不会超过间隔[a..b]的长度。并且答案将是 min(M [a] [P],M [b - (1
答案 1 :(得分:2)
对于静态数组,正如您所提到的,最快的解决方案是使用O(n)preproc的O(1)。但在实践中,您可能希望使用以下方法之一,这也适用于动态数组,在我看来更容易理解和编码:
答案 2 :(得分:1)
对于那些了解俄语的人来说,这就是解决方案:http://e-maxx.ru/algo/rmq 对于那些不懂俄语的人,抱歉,我还没找到什么。如果有人会找到,请编辑我的答案。
答案 3 :(得分:1)
一个简单的解决方案是创建一个二维数组,其中一个条目[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/