求解区间最值 - RMQ - ST 算法介绍
解析
ST 算法是 RMQ(Range Minimum/Maximum Query)中一个很经典的算法,它天生用来求得一个区间的最值,但却不能维护最值,也就是说,过程中不能改变区间中的某个元素的值。O(nlogn) 的预处理和 O(1) 的查询对于需要大量询问的场景是非常适用的。接下来我们就来详细了解下 ST 算法的处理过程。
比如有如下长度为 10 的数组:
1 3 2 4 9 5 6 7 8 0
我们要查询 [1, 7] 之间的最大值,如果采用朴素的线性查找,复杂度O(n),而 ST 算法却只需要 O(1)的时间复杂度,因为 ST 算法预处理了一个 dp 数组。
我们用 dp[i][j] 表示从 i 开始的 2^j 个数的最值,表示 dp[i][j] “管辖” index=i 开始的 2^j 个数字,那么很显然,任何一段区间都能被两个 dp 元素管辖到。比如上面说的 [1, 7],就能被dp[1][2] 和 dp[4][2]管辖到,而 max(dp[1][2], dp[4][2])也就是[1, 7] 的最值了。
如何得出是 dp[1][2] 和 dp[4][2] 这两个元素?很简单,让dp[1][n](2^n <= 区间个数)中的n尽可能大就得到了第一个元素,从而可以推得第二个元素,两个元素的管辖范围大小是一样的。
这样我们只需预处理一个 dp 数组就可以了,而这个预处理是一个动态规划的过程,转移方程为:
dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
而 dp 数组的预处理和 RMQ 的求解过程正好是个逆过程。
实战
POJ 上有一道 ST 算法的模板题 Balanced Lineup,只需预处理两个数组即可,一个表示最大值,另一个表示最小值。
完整代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define N 50005
int maxn[N][32], minn[N][32];
int a[N];
void ST(int n) {
for (int i = 1; i <= n; i++)
maxn[i][0] = minn[i][0] = a[i];
int k = log(n * 1.0) / log(2.0);
for (int j = 1; j <= k; j++)
for (int i = 1; i <= n; i++) {
if (i + (1 << j) - 1 > n) break;
maxn[i][j] = max(maxn[i][j - 1], maxn[i + (1 << (j - 1))][j - 1]);
minn[i][j] = min(minn[i][j - 1], minn[i + (1 << (j - 1))][j - 1]);
}
}
int getAns(int x, int y) {
int k = log(y - x + 1.0) / log(2.0);
return max(maxn[x][k], maxn[y + 1 - (1 << k)][k]) - min(minn[x][k], minn[y + 1 - (1 << k)][k]);
}
int main() {
int n, cas;
scanf("%d%d", &n, &cas);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
ST(n);
while (cas--) {
int x, y;
scanf("%d%d", &x, &y);
printf("%d\n", getAns(x, y));
}
return 0;
}
Javascript模板:
var G = {
dp: [], // dp[i][j] 表示从 index=i 开始的连续 2^j 个元素中的最值
init: function(a) {
var n = a.length;
for (var i = 0; i < n; i++)
G.dp[i] = [], G.dp[i][0] = a[i];
var k = ~~(Math.log(n) / Math.log(2));
for (var j = 1; j <= k; j++)
for (var i = 0; i < n; i++) {
if (i + (1 << j) - 1 >= n) break;
// 如果求区间最小值,改为 Math.min() 即可
G.dp[i][j] = Math.max(G.dp[i][j - 1], G.dp[i + (1 << (j - 1))][j - 1]);
}
},
getAns: function(x, y) {
var k = ~~(Math.log(y - x + 1) / Math.log(2));
// 如果求区间最小值,改为 Math.min() 即可
return Math.max(G.dp[x][k], G.dp[y + 1 - (1 << k)][k]);
}
};
var a = [1, 3, 2, 4, 8, 7, 6, 5, 9, 0] // 需要求 RMQ 的数组
G.init(a);
// test cases
for (var i = 0; i < 10; i++)
for (var j = i + 1; j < 10; j++) {
var tmp = a.slice(i, j + 1)
, normalAns = Math.max.apply(null, tmp)
, stAns = G.getAns(i, j);
if (normalAns !== stAns)
console.log('Algorithm went wrong!');
}
求解区间最值 - RMQ - ST 算法介绍的更多相关文章
- 【原创】RMQ - ST算法详解
ST算法: ID数组下标: 1 2 3 4 5 6 7 8 9 ID数组元素: 5 7 3 1 4 8 2 9 8 1.ST算法作 ...
- HDU 3183 - A Magic Lamp - [RMQ][ST算法]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3183 Problem DescriptionKiki likes traveling. One day ...
- 关于基础RMQ——ST算法
RMQ,Range Maximum/Minimum Query,顾名思义,就是询问某个区间内的最大值或最小值,今天我主要记录的是其求解方法--ST算法 相对于线段树,它的运行速度会快很多,可以做到O( ...
- [POJ3264]Balanced Lineup(RMQ, ST算法)
题目链接:http://poj.org/problem?id=3264 典型RMQ,这道题被我鞭尸了三遍也是醉了…这回用新学的st算法. st算法本身是一个区间dp,利用的性质就是相邻两个区间的最值的 ...
- POJ 3264 Balanced Lineup RMQ ST算法
题意:有n头牛,编号从1到n,每头牛的身高已知.现有q次询问,每次询问给出a,b两个数.要求给出编号在a与b之间牛身高的最大值与最小值之差. 思路:标准的RMQ问题. RMQ问题是求给定区间内的最值问 ...
- RMQ st算法 区间最值模板
#include<bits/stdc++.h> ; ; int f[N][Logn],a[N],lg[N],n,m; int main(){ cin>>n>>m; ...
- Balanced Lineup:线段树:区间最值 / RMQ
不要被线段树这个名字和其长长的代码吓到. D - Balanced Lineup Description For the daily milking, Farmer John's N cows (1 ...
- POJ 3368 Frequent values RMQ ST算法/线段树
Frequent values Time Limit: 2000MS Memory Lim ...
- RMQ(模板 ST 区间最值,频繁的间隔时间)
PS: 介绍:http://blog.csdn.net/liang5630/article/details/7917702 RMQ算法.是一个高速求区间最值的离线算法,预处理时间复杂度O(n*log( ...
随机推荐
- 记录git多人协作开发常用的流程,供新手参考
声明:博主写的博客都是经过自己总结或者亲测成功的实例,绝不乱转载.读者可放心看,有不足之处请私信我,或者给我发邮件:pangchao620@163.com. 写作目的: 记录一下我看完廖学锋老师的gi ...
- phonegap学习笔记
[windows下安装] 1 先安装node.js: http://nodejs.org/ 2 CMD下运行: C:\> npm install -g phonegap [创建项目] CMD下运 ...
- mysql 5.5多实例部署【图解】
mysql5.5数据库多实例部署,我们可以分以下几个步骤来完成. 1. mysql多实例的原理 2. mysql多实例的特点 3. mysql多实例应用场景 4. mysql5.5多实例部署方法 一. ...
- SQL Server:孤立用户详解
SQL Server 的用户安全管理分两层,整个SQL Server 服务器一层,每个数据库一层. 在服务器层的帐号,叫登录账户(SQL Server:服务器角色),可以设置它管理整个SQL Serv ...
- activiti入门
一.Activiti简介 Activiti 是一个针对商务人士. 开发人员和系统管理员的轻量级的工作流和业务流程管理 (BPM) 平台.它的核心是Java的高速和可靠的 BPMN 2 流程引擎.它是开 ...
- x01.FileProcessor: 文件处理
姚贝娜落选,意味着好声音失败.“我们在一起”的精彩亮相,正如同她的歌声,愈唱愈高,直入云霄. 文件处理,无外乎加解密,加解压,分割合并.本着“快舟"精神,花了两天时间,写了个小程序,基本能满 ...
- ES6块级作用域及新变量声明(let)
很多语言中都有块级作用域,但JS没有,它使用var声明变量,以function来划分作用域,大括号“{}” 却限定不了var的作用域.用var声明的变量具有变量提升(declaration hoist ...
- uva 12745 Wishmaster(2-sat)
12745 Wishmaster view code#include <iostream> #include <cstdio> #include <algorithm&g ...
- Java开发之JSP行为
一.Java Bean行文 1.重点说明 Java Bean行为是一组与Java Bean相关的行为,包括useBean行为.setProperty行为.getProperty行为等.Java Bea ...
- Java开发之文件上传
文件上传有SmartUpload.Apache的Commons fileupload.我们今天介绍Commons fileupload的用法. 1.commons-fileupload-1.3.1.j ...