您的位置:首页 > 其它

Sparse Table算法 - RMQ问题的简单高效算法

2016-02-15 19:36 323 查看
Sparse Table算法是用来解决一类RMQ问题的O(nlog2n)的算法,而且代码非常好写,在本质上是一个动态规划,写起来其实也就是几十行。那么在这里的RMQ问题是什么呢?RMQ问题,中文名应该是范围(区间)最(小)值问题,简单描述一下,就是先给出一个序列,然后不断求若干个区间中的一个最值。比如说最小值,最大值之类。像堆那样的数据结构能解决的问题是整个序列的最值问题,而RMQ问题则是序列一段的最值,万万不能弄混了。 Sparse Table算法是一种动态规划算法,精髓就是动态规划,再加上了一些分治,能够做到O(nlog2n)预处理,O(log2n)单次查询的神级复杂度,甚至可以和线段树比肩,而且要注意的是常数要小很多! 动态规划的方程如下:设f[i][j]表示从i开始,后2^j个数中的最值,则f[i][j]=compare{f[i][j-1],f[i+2^(j-1)][j-1]}。 其中compare{ , }函数就是所谓的最值函数(我定义的),比如说我们要找最小值,则compare{ , }=min{ , },最大值则是compare{ , }=max{ , }。很容易发现,这个动态规划的本质,就是分治!将一个整的区间分成两个较小的区间,又能够看出在一个长度为n的序列中,2^j<=n,则j最多是log2(n)+1。而i总共有n种可能的值,则总的预处理复杂度就是O(nlog2n)。 那么最后的值怎么达到呢?假如我们要求[begin,end]区间内的最小值,则在预处理之后分解一下end-begin的二进制,则就可以将[begin,end]的最小值问题分解成若干个长度为2^j的区间了(j为相应的值)。 这就是Sparse Table算法,可算是简洁了吧?但是下面让我们剖析一下其的本质。 Sparse Table算法其实是将一个大的区间不断二分,那我们如果以记忆化搜索的角度,看一下求[1,n]的最小值呢?假设n=16,那么中间涉及的查询有:
1 [1,16]2 [1,8] [9,16]3 [1,4] [5,8] [9,12] [13,16]4 [1,2] [3,4] [5,6] [7,8] [9,10] [11,12] [13,14] [15,16]5 [1,1] [2,2] [3,3] [4,4] [5,5] [6,6] [7,7] [8,8] [9,9] [10,10] [11,11] [12,12] [13,13] [14,14] [15,15] [16,16]
所以……这个算法的本质,就是一棵线段树的简化查询算法。而这也是我在学了一段时间线段树后的想法,那就是为什么好像什么东西都和线段树有关……RMQ问题的这个解法,胜者树,二分搜索,似乎都有一点线段树的思想。但是线段树其实也应该说是集合了这些思想,不然怎么会能够以比平衡树短(好吧如果你平衡树打得熟的话这句话请无视)的代码实现比平衡树更为快的时间复杂度呢(虽说功能没那么多)?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: