Range Minimum Query(RMQ) 是一个用O(N*logN)进行预处理,用O(1)时间在数组的一段区间中查找最小元素的值的算法
Lowest Common Ancestor(LCA) 是寻找树中两个节点最近祖先的算法,LCA可以在O(N)时间内归约为RMQ
参考文章:RangeMinimumQueryAndLowestCommonAncestor
我写的RMQ类:RMQ
package SDJL;
public class RMQ
{
private int[] datas;
private int[][] m;//m[i][j]保存了从第i个位置开始长度为2^j区间中的最小值
private int n, log_n;//n表示数组长度,log_n表示2为底n的对数
public RMQ(int[] datas)
{
this.datas = datas;
this.n = datas.length;
for (this.log_n = 0; 1 << this.log_n <= n; this.log_n++) ;//计算log_n
//以下部分为计算m,用时O(N*logN)
this.m = new int[this.n][this . log_n];
for (int i = 0; i < this.n; i++)
{
m[i][0] = this.datas[i];
}
for (int j = 1; j < this.log_n; j++)
{
int power_j = 1 << j;
int power_jMinus1 = 1 << (j - 1);
for (int i = 0; i + power_j - 1 < this.n; i++)
{
if (this.m[i][j - 1] < this.m[i + power_jMinus1][j - 1])
{
this.m[i][j] = this.m[i][j - 1];
}
else
{
this.m[i][j] = this.m[i + power_jMinus1][j - 1];
}
}
}
}
//获得两个区间中的最小值,用时O(1)
public int getMinimum(int stratIndex, int endIndex)
{
/*
*把区间分为左、右两部分,每个部分有2^k长,一般情况下中间部分有重叠
*/
int k = (int)(Math.log(endIndex - stratIndex + 1) / Math.log(2));
//在左、右两部分中选择一个最小值
if (this.m[stratIndex][k] <= this.m[endIndex - (1 << k) + 1][k])
{
return this.m[stratIndex][k];
}
else
{
return this.m[endIndex - (1 << k) + 1][k];
}
}
public int getData(int index)
{
return this.datas[index];
}
public int length()
{
return this.datas.length;
}
}
public class RMQ
{
private int[] datas;
private int[][] m;//m[i][j]保存了从第i个位置开始长度为2^j区间中的最小值
private int n, log_n;//n表示数组长度,log_n表示2为底n的对数
public RMQ(int[] datas)
{
this.datas = datas;
this.n = datas.length;
for (this.log_n = 0; 1 << this.log_n <= n; this.log_n++) ;//计算log_n
//以下部分为计算m,用时O(N*logN)
this.m = new int[this.n][this . log_n];
for (int i = 0; i < this.n; i++)
{
m[i][0] = this.datas[i];
}
for (int j = 1; j < this.log_n; j++)
{
int power_j = 1 << j;
int power_jMinus1 = 1 << (j - 1);
for (int i = 0; i + power_j - 1 < this.n; i++)
{
if (this.m[i][j - 1] < this.m[i + power_jMinus1][j - 1])
{
this.m[i][j] = this.m[i][j - 1];
}
else
{
this.m[i][j] = this.m[i + power_jMinus1][j - 1];
}
}
}
}
//获得两个区间中的最小值,用时O(1)
public int getMinimum(int stratIndex, int endIndex)
{
/*
*把区间分为左、右两部分,每个部分有2^k长,一般情况下中间部分有重叠
*/
int k = (int)(Math.log(endIndex - stratIndex + 1) / Math.log(2));
//在左、右两部分中选择一个最小值
if (this.m[stratIndex][k] <= this.m[endIndex - (1 << k) + 1][k])
{
return this.m[stratIndex][k];
}
else
{
return this.m[endIndex - (1 << k) + 1][k];
}
}
public int getData(int index)
{
return this.datas[index];
}
public int length()
{
return this.datas.length;
}
}