目录
一、介绍
1.1 倍增
1.2 稀疏表ST
二、原理
三、代码实现
3.1 创建稀疏表
3.2 初始化数值
3.3 ST查询
一、介绍
1.1 倍增
倍增的思想是在数据空间特别大的时候,快速进行查找搜索而使用的。例如想要在一个数据量为n的递增数组中查找到等于x的下标,最简单想到的就是遍历整个数组。而现在以步长进行搜索,若x小于该节点,则加大增量继续比较;否则减小增量继续比较,知道搜索到目标节点。
1.2 稀疏表ST
稀疏表采用了倍增的思想,在O(nlogn)时间构造了一个二维表之后,在O(1)时间在线查询[l ,r]区间的最值,有效解决区间最值问题。这是一种不支持在线修改,对静态数据进行搜索的算法。
简单来说,稀疏表就是,对于一个区间,想要快速找到其中的最大值(最小值),于是就划分为多个区间,按照一定的步长找到对应每一个小模块的最大值后映射到一个二维表中,这样下一次查找最值的时候,就能按照规定的规律直接进行检索。
二、原理
定义 表示区间的最值,其中 i 为该区间的起始点,j为搜索步长,区间长度为 。
递推公式:
将区间划分为两个子区间后求解迭代最值。如果是创建最小值,则对公式稍微进行修改:
第一个区间为,所以第二个区间是从开始的,这里稍微做一下解释
三、代码实现
3.1 创建稀疏表
std::vector<std::vector<int>> sparseTable;
3.2 初始化数值
函数输入需要放入稀疏表中的数组
稀疏表的第一列是数组排入,从第二列开始映射数据。
例如:[7,2,3,0,5,8,4,6]为输入数据,则
数据量n = 8;最大检索量logn = 4
创建的稀疏表为
void createSparseTable(const std::vector<int>& nums)
{
int n = nums.size(); //数据量
int logn = log2(n) + 1; //稀疏表的列数,算是最大检索量
sparseTable.resize(n, std::vector<int>(logn));
/*
*稀疏表是将所有的元素都按列进行排放,横向填充
*/
//填充第一列
for (int i = 0; i < n; i++)
{
sparseTable[i][0] = nums[i];
}
//递推公式: F[i,j]=max(F[i,j-1],F[i+2^(j-1)][j-1])
//填充其余列
for (int j = 1; j < logn; j++)
{
for (int i = 0; i + (1 << j) <= n; i++)
{
sparseTable[i][j] = std::max(sparseTable[i][j - 1], sparseTable[i + (1 << (j - 1))][j - 1]);
}
}
}
3.3 ST查询
l,r分别为区间的左端点和右端点
//查询区间最值
int query(int l, int r)
{
int len = r - l + 1;
int k = log2(len); //查询步长
return std::max(sparseTable[l][k], sparseTable[r - (1 << k) + 1][k]); //时间复杂度为O(1)的查询
}