RMQ问题,即求区间最大最小值的问题:对于长度为N的数列,询问若干次RMQ(A,I,J)(I<=J<=N),求[I,J]的最大(小)值。
我们可以采取朴素的直接搜的算法,如果数据非常大的话,直接搜就会爆时间爆的很惨。然后我们可以采取二分法来建一棵可爱的线段树,通过线段树来求。但是线段树的建立和查询都是O(nlogn)的时间, 那有没有更好的办法呢?
于是便诞生了一种神奇的叫做ST算法的东西,他的建立也是O(nlogn)的时间复杂度,但是查询只需要O(1),可是为什么我们没有用它来彻底替代线段树呢,因为他很麻烦么?当然不麻烦,他甚至还要比线段树简单。可是他有一个致命的缺陷,修改十分费劲。我们如果不需要修改数据,只需要不断返回最值,那么这个办法无疑要比线段树优越很多。
首先这个算法用了动态规划的办法,在谈论他的办法之前,我们先来想一个朴素的动归。f[I,J]=MAX(F[I,K],F[K+1,J]),这个很朴素,也很好理解。他就是把这个区间分成两段,求出每一段的最值来就好了,至于K值,等于i就可以。我们只要把F[I,J]=I初始化,然后循环求就好了。他的建立时间复杂度是O(N^2),查询只需要O(1),空间复杂度也是O(N^2),这个复杂度就有些致命了,20000的数据都有可能会卡掉的。
所以我们可以找一个办法优化这个算法。我们先来看一下这个dP方程,我们可不可以把他修改一下,改成F[I,J]=MAX(F[I,K],F[I+k+1,J-k-2])。我需要先解释一下这个方程,这里F[I,J]表示的不再是[I,J]的最值,而是[I,I+J-1]的最值,然后把这个区间分成两部分一部分是[I,I+K],另一部分是[I+K+1,I+J-1],至于这个K,初始化后,等于0就可以。
我们来考虑一下,有一个很不起眼的变量,他叫做K,我之前说过K等于XX就可以,其实如果k不等于XX,我们依旧可以通过一些处理让这个算法可行,那么我们不妨找些别的k,说不定会有奇效。
我们的目的是得到一个比线段树简单的算法,那么我们需要O(nlongn)的复杂度,那我们需要用到二分。我们可以把K转化为一个和2有关系的数字,2^i。这样一来我们就得到了这样一个方程。F[i,j]=max(F[i,j-1],F[i+2^(j-i),j-1])。然后我们再求[I,J]的区间最值,就只需要求[X,X+2^I-1]和[Y-2^i+1,Y],分别对应F[X,I]和F[Y-2^I+1,I]。可能你会疑惑,这样如何保证两边的区间把[X,Y]刚好都包括进来了呢,其实我们保证两个区间能把[X,Y]包括进来,而且不包括其他数字就可以,没必要保证刚好。