几何平均值最大子数组

题目描述

从一个长度为N的正数数组numbers中找出长度至少为L且 几何平均值 最大的子数组,并输出其位置和大小。
(K个数的 几何平均值 为K个数的乘积的K次方根)
若有多个子数组的几何平均值均为最大值,则输出长度最小的子数组。
若有多个长度相同的子数组的几何平均值均为最大值,则输出最前面的子数组。

输入描述

  • 第一行输入为N、L
    • N表示numbers的大小 1 ≤ N ≤ 100000 1\le N\le 100000 1N100000
    • L表示子数组的最小长度 1 ≤ L ≤ N 1\le L\le N 1LN
  • 之后的N行表示numbers中的N个数,每个一行 1 0 − 9 ≤ n u m b e r s [ i ] ≤ 1 0 9 10^{-9} \le numbers[i] \le 10^9 109numbers[i]109

输出描述

  • 输出子数组的位置(从 0 开始计数)和大小,中间用一个空格隔开。

备注

  • 用例保证除几何平均值为最大值的子数组外,其他子数组的几何平均值至少比最大值小 1 0 − 10 10^{-10} 1010倍数。

用例

用例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);
    }

你可能感兴趣的:(算法学习心得记录,算法)