本文主要是介绍区间最值查寻(RMQ问题),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
RMQ问题就是区间最小值问题,这是一个非常经典的题,
由他引申出来的也是不计其数最多的是给出一个区间,然后输入多组区间端点,求输入区间的最小值。
每次用循环来计算一个最小值显然不够快,怎么办呢?
实践中最常用的是Tarjan的 Sparse-Table算法,它的预处理时间是O(nlogn),但是查询只需要O(1),而且常数很小。
它的思想很简单,就是递推+二分的思想。我们先定义一个二维数组d[i][j],
代表从 i 开始,长度为2的j次幂的区间中的最小值
然后写出递推公式 d[i][j] = min( d[i][j – 1], d[i + (1 << (j - 1))][j - 1]),
其中1 << (j - 1) 代表2的 j – 1次幂查询操作很简单,
我们要先求出一个数k 让2的k次幂小于等于R-L+1,
那么d[L][k]与d[R-(1 << k) + 1][k]就覆盖了整个L到R的区间,读者可自行验证。
现在就可以写出完整的代码了
#include<stdio.h>
#include<algorithm>
using namespace std;
int a[100];
int dp[100][10];
int query(int L, int R){
int k = 0;
while (1 << (k + 1) <= R - L + 1)
k++;
return min(dp[L][k], dp[R - (1 << k) + 1][k]);
}
int main(){
int n, i, j;
scanf("%d", &n);
for (i = 1; i <= n; i++){
scanf_s("%d", &a[i]);
dp[i][0] = a[i];
}
for (i = 1; (1 << i) <= n; i++){
for (j = 1; j + (1 << (i - 1)) <= n; j++){
dp[j][i] = min(dp[j][i - 1], dp[j + (1 << (i - 1))][i - 1]);
}
}
int L, R;
scanf("%d%d", &L, &R);
printf("%d\n", query(L, R));
return 0;
}
附上一个相关练习[南阳oj上的一道题 很好](http://acm.nyist.net/JudgeOnline/problem.php?pid=119)
这篇关于区间最值查寻(RMQ问题)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!