题目描述
从一个长度为N
的正数数组numbers
中找出长度至少为L
且 几何平均值 最大的子数组,并输出其位置和大小。
(K个数的 几何平均值 为K个数的乘积的K次方根)
若有多个子数组的几何平均值均为最大值,则输出长度最小的子数组。
若有多个长度相同的子数组的几何平均值均为最大值,则输出最前面的子数组。
输入描述
- 第一行输入为
N、L
N
表示numbers
的大小L
表示子数组的最小长度
- 之后的
N
行表示numbers
中的N
个数,每个一行
输出描述
- 输出子数组的位置(从 0 开始计数)和大小,中间用一个空格隔开。
备注
- 用例保证除几何平均值为最大值的子数组外,其他子数组的几何平均值至少比最大值小倍数。
用例
用例1
- 输入
3 2
2
2
3
- 输出
1 2
- 说明
- 长度至少为 2 的子数组共 3 个,分别是
{2, 2}、{2, 3}、{2, 2, 3}
- 其中
{2, 3}
的几何平均值最大,故输出其位置 1 和 长度2
用例2
- 输入
10 2
0.2
0.1
0.2
0.2
0.2
0.1
0.2
0.2
0.2
0.2
- 输出
2 2
- 说明
- 有多个长度至少为 2 的子数组的几何平均值为 0.2,其中长度最短的为 2,也有多个。
- 长度为 2 且几何平均值为 0.2 的子数组最前面的那个为第二个数开始的两个 0.2 组成的子数组
代码展示
private static void maxGeoSubArray(double[] numbers, int L) {
// 首先构造前缀积数组
int n = numbers.length;
double[] mul = new double[n+1];
// 初始化第一个元素 为 0
mul[0] = 1.0;
// 填充前缀积数组数据
for(int i = 0;i < n;i++) {
mul[i + 1] = mul[i] * numbers[i];
}
// 初始化左右边界变量
int l = 0,r = 0;
// 保存最大值
double ans = 0.0;
// 双重遍历,去找到 最大几何平均值
for(int i = 0;i <= n - L;i++) {
for(int j = i + L - 1;j < n;j++) {
// 这个时候,计算区间 [i, j] 的几何平均值 j - i + 1
double t = mul[j+1] / mul[i];
int len = j - i + 1;
// 开 len 次方根
double avg = Math.pow(t, 1.0 / len);
// 根据备注要求,几何平均值的大小至少要保证比最大值 小 10^{-10} 次方倍
if(Math.abs(avg - ans) > Math.max(avg, ans) / Math.pow(10, 10) && avg >= ans) {
if(avg == ans) {
int local = r - l + 1;
if(len > local) {
r = j;
l = i;
}
} else {
ans = avg;
r = j;
l = i;
}
}
}
}
// 最终遍历最后然后输出结果 输出 位置 和 长度
System.out.print(l + " ");
System.out.print(r - l + 1);
}