【Leetcode】644. Maximum Average Subarray II

这篇博客介绍了如何解决LeetCode上的一个题目,即寻找给定数组中长度大于等于k的平均值最大的子数组。解决方案采用了二分查找算法,首先确定答案可能的范围,然后在每次二分中检查是否存在满足条件的子数组。通过维护前缀和与最小值,能够在O(nlog(M-m))的时间复杂度内找到答案。
摘要由CSDN通过智能技术生成

题目地址:

https://leetcode.com/problems/maximum-average-subarray-ii/

给定一个长 n n n数组 A A A,再给定一个小于等于 n n n的正整数 k k k,问 A A A里长度大于等于 k k k的平均值最大的子数组的平均值是多少。平均值以浮点数形式返回,有 1 0 − 5 10^{-5} 105的误差都算正确。

思路是二分答案,设 A A A的最大值是 M M M,最小值是 m m m,那么答案的范围是 [ m , M ] [m,M] [m,M],对于二分出的答案 x x x,只需要判断一下 A A A中是否存在一个长度大于等于 k k k的子数组的平均值是大于等于 x x x的,等价于问 [ A [ i ] − x ] i [A[i]-x]_i [A[i]x]i这个数组是否存在长度大于等于 k k k的且和大于等于 0 0 0的子数组。对于这个问题,可以这样做,设新数组 C = [ A [ i ] − x ] i C=[A[i]-x]_i C=[A[i]x]i,先求一下 C C C的长 k k k的前缀,如果该前缀已经非负了那当然存在,否则枚举子数组右端点 C [ j ] C[j] C[j],只需看一下以 C [ 0 : j − k ] C[0:j-k] C[0:jk]为右端点的前缀(注意,这里还要把 0 0 0前缀考虑进去)里是否有小于等于 C [ j ] C[j] C[j]的,如果有那就存在。可以用一个变量动态记录前缀里的最小值。代码如下:

public class Solution {
    public double findMaxAverage(int[] nums, int k) {
        double l, r;
        // 算一下二分答案的答案范围
        l = r = nums[0];
        for (int i = 1; i < nums.length; i++) {
            l = Math.min(l, nums[i]);
            r = Math.max(r, nums[i]);
        }
        
        double eps = 1E-5;
        // 开始二分答案
        while (l + eps < r) {
            double m = l + (r - l) / 2;
            // 看一下nums里是否存在长度大于等于k的且平均值大于等于m的子数组
            if (check(nums, m, k)) {
                l = m;
            } else {
                r = m;
            }
        }
        
        return l;
    }
    
    private boolean check(int[] A, double t, int k) {
        double cur = 0, prev = 0;
        // 先算一下A - t这个数组的k前缀
        for (int i = 0; i < k; i++) {
            cur += A[i] - t;
        }
        
        // 如果这个前缀已经非负了,那说明存在,返回true
        if (cur >= 0) {
            return true;
        }
        
        // min存A[0 : i - k]为右端点的前缀里的最小前缀值;
        // 注意0也要考虑进去,所以这里初始化为0而不是初始化为正无穷
        double min = 0;
        for (int i = k; i < A.length; i++) {
            cur += A[i] - t;
            prev += A[i - k] - t;
            min = Math.min(min, prev);
            
            if (cur - min >= 0) {
                return true;
            }
        }
        
        return false;
    }
}

时间复杂度 O ( n log ⁡ ( M − m ) ) O(n\log (M-m)) O(nlog(Mm))

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值