[关闭]
@Zh1Cheung 2018-03-16T12:32:19.000000Z 字数 1562 阅读 698

Sparse Table算法

一:背景

Sparse Table算法(以下简称ST算法)是用来解决以下问题的,

区间最值查询(Range Minimum/Maximum Query,简称RMQ问题):对于长度为n的数组array[],回答若干询问RMQ(array, i, j),返回数组array[]中下标在i,j之间的最小或最大值。

找一个区间最值,最简单的直接比较,复杂度是,所以如果查找次数很少,用ST算法没有意义。ST算法的应用场景就是要对一个数串查询多次的情况。

算法的基本思想就是对串中所有可能的区间组合的最值用二维数组保存,也就是所谓的预处理,查询时直接通过数组下标获取,的时间。下面采用动态规划来对数串进行预处理,也就是填充二维数组。

二:算法过程分析

我们以区间最大值查询为例。

表示数组在区间的最大值。(此即DP的状态,区间长度正好为

很容易发现对于。(此即DP的初值)

最后看下DP的转移方程。我们把所表示的区间平均分成两段,也就是:

于是得到转移方程:

代码如下:

void RMQ(int array[], int n)
{
    for (int i = 0; i < n; i++)
        f[i][0] = array[i];

    int k = log(n) / log(2.0);
    for (int j = 1; j <= k; j++)
        for (int i = 0; i < n; i++)
            if (i + (1 << j) - 1 < n)
                f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}

预处理完成。最后查询操作代码怎么写呢?对于查询区间,我们分成两部分,即下图的两个矩形,长度相等,大小等于

三:完整代码

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

const int ROW = 1000;
const int COLUMN = 10;  // log(1000)/log(2.0) ~ 9.96
int f[ROW][COLUMN];

void RMQ(int array[], int n)
{
    for (int i = 0; i < n; i++)
        f[i][0] = array[i];

    int k = log(n) / log(2.0);
    for (int j = 1; j <= k; j++)
        for (int i = 0; i < n; i++)
            if (i + (1 << j) - 1 < n)
                f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}

int main()
{
    int array[] = { 3,2,4,5,6,8,1,2,9,7 };
    int n = sizeof(array) / sizeof(int);

    RMQ(array, n);

    cout << "数组的下标范围为:0 -- " << n - 1 << ",";
    cout << "请输入需要查询的区间: \n";
    int i, j;
    while (cin >> i >> j)
    {
        int k = log(j - i + 1.0) / log(2.0);
        int max_ans = max(f[i][k], f[j - (1 << k) + 1][k]);
        cout << "最大值是: " << max_ans << endl << endl;
    }
    return 0;
}

运行截图如下:

四:总结

整体来说,ST算法的时间复杂度为,其中为查询次数。

当然对于RMQ问题,不止ST一个方法,线段树也可以。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注