目录

题目来源

题目描述

示例

提示

题目解析

算法源码


题目来源

644. 子数组最大平均数 II - 力扣(LeetCode)

题目描述

给定一个包含 n 个整数的数组nums,找到最大平均值连续子序列,且长度大于等于 k。并输出这个最大平均值。

示例

输入 nums = [1,12,-5,-6,50,3], k = 4
输出 12.75
说明 当长度为 5 的时候,最大平均值是 10.8,
当长度为 6 的时候,最大平均值是 9.16667。
所以返回值是 12.75。
输入 nums = [1,12,-5,-6,50,3,90,80,-100], k = 4
输出 55.75
说明

提示

  • 1 <= k <= n <= 10,000
  • 数组nums中的元素范围是 [-10,000, 10,000]
  • 答案的计算误差小于 10^-5

题目解析

本题还是比较难,在leetcode中也是hard级别。

本题最简单的解题思路是,暴力枚举出nums的所有长度大于等于k的连续子序列,然后分别求解这些连续子序列的平均数,返回最大的。

这里,我们可以用双重for循环来枚举出所有长度大于等于k的连续子序列,外层是连续子序列的左侧起点,内层是连续子序列的右侧终点,但是这个时间复杂度是O(n^2),对于 1 ≤ n ≤ 10000 的数量级来说,是肯定会超时的。

因此上面思路不可取。

本题目前最优的解法如下:

第一步、通过二分法,找出所求子序列的可能的平均值。

这里,为什么要用二分法呢?

举个例子,有一个数组[1,2,3],请思考:

  • 它的平均值会大于3吗?
  • 它的平均值会小于1吗?

答案很显然,都不会。因为该数组的最大值为3,因此这个数组的平均值最大只可能为3,不可能超过3;同理这个数组的最小值为1,因此这个数组的平均值最小只能为1,不可能小于1。

因此,我们很容易得出一个结论,一个数组nums的平均值avg,必然满足:

min(nums) <= avg <= max(nums)

因此,我们可以用二分法,在min(nums)和max(nums)区间内找到一个符合要求平均值。

那么二分查找,何时结束呢?

更具题目备注:

答案的计算误差小于 10^-5

即,当二分法的查找区间,两端距离小于10^-5,就可以结束二分查找了。

嗯嗯,现在,我们已经通过二分查找,找到一个可能是子序列最大平均值的midAvg了,现在该如何验证这个midAvg是不是符合要求的呢?

符合啥要求呢?

即数组nums中所有的长度>=k的连续子序列的平均值都<= midVal。

此时midVal就是题解。

但是,上面验证方案,需要求解所有长度>=k的连续子序列,并求平均值。这不是我们所期望的。

我们可以反向思考一下,如果存在一个长度>=k的连续子序列,其平均值 > midVal,那么是不是说当前这个midVal就不是一个符合要求,并且,还有透露出一个重要信息,那就是这个midVal取小了!!

因此下次二分查找时,我们缩小查找范围,因该将此时的midVal作为新范围的左边界,这样再次二分时,取得的新midVal就会变大。

同理,如果所有的长度大于等于k的连续子序列的平均值都 < midVal,则说明该midVal也不是一个符合要求的,并且取大了,因此下次二分查找时,我们应该缩小右边界,让此时的midVal作为新的右边界,这样下次继续二分时,新midVal就会变小。

到此,关于midVal的取值逻辑已经阐述完毕,现在最大的问题是:

上面的逻辑,我们可能需要找出长度大于等于k的所有的连续子序列,然后求平均值,这个在暴力枚举时已经说过了,会超时。

因此,我们需要一个算法,可以高效的找出长度大于等于k的所有的连续子序列。

这里用到了动态规划的前缀和思想。请看下面例子:

有一个数组nums = [a1, a2, a3, a4, a5, ... , aN],现在要求从其中找到一个长度大于等于k的子数组。

首先,我们利用动态规划前缀和思想,求出以每一个数组元素为结尾的前缀和,公式如下

  • dp[0] = nums[0]
  • dp[i] = dp[i-1] + nums[i]

dp[i]表示0~i范围内所有元素的和。

那么nums中一个长度等于k的子数组是不是可以理解为:

从0~i区间内,挖去0~i-k区间,剩余的 i-k ~ i 不就是一个长度为k子数组吗

如果要我们求解长度等于k的子数组的和,那不就是:

dp[i] - dp[i-k]

但是现在,本题要求解的是:

长度 大于等于 k 的子数组,且该子数组的和要最大

首先,长度大于等于k的实现很简单,就是将

从0~i区间内,挖去0~i-x区间,其中x>=k,这样的话剩下的区间不就是一个大于等于k的子数组嘛

之后,是子数组的和最大,这个实现和被挖去的区间有关:

现在被挖去的区间可能为:

0~0

0~1

0~2

...

0~i-k

如果想让剩余区间的和最大,那么被挖去的区间的和要最小!!

即,在上面被挖去的区间内找到一个最小和的区间,而这个最小和的区间我们可以在求解前缀和的过程中记录下来,具体实现看下面代码。

现在,我们已经得到了一个  最大和 且 长度>=k的 子数组。

但是现在我们需要求解的是  最大平均值  且 长度 >= k 的子数组。

所以,现在的问题就是,把对最大平均值的求解,转化为对:最大和的求解。

这个很简单,只要把nums数组元素 都减去 midVal 即可。

原理是,本来我们是要,求解nums 某个区间内元素和的平均值,现在假设该区间的元素和平均值是avg,那么是不是等价于 验证: (a1 + a2 + a3 + ... + aN) / N == avg

再变化下,是不是等价于

a1 + a2 + a3 + ... + aN == N * avg

再变化下,是不是等价于

(a1 - avg)  +  (a2 - avg) + (a3 - avg)  + ... + (aN - avg) == 0

如果avg取大了,则 (a1 - avg)  +  (a2 - avg) + (a3 - avg)  + ... + (aN - avg) < 0

如果avg取小了,则 (a1 - avg)  +  (a2 - avg) + (a3 - avg)  + ... + (aN - avg) > 0

JS算法源码

function getResult(nums, k) {let minAvg = Infinity;let maxAvg = -Infinity;for (let num of nums) {minAvg = Math.min(num, minAvg);maxAvg = Math.max(num, maxAvg);}const diff = 1e-5;while (maxAvg - minAvg >= diff) {let midAvg = (minAvg + maxAvg) / 2;if (check(nums, k, midAvg)) {minAvg = midAvg;} else {maxAvg = midAvg;}}return minAvg.toFixed(2);
}function check(nums, k, avg) {let sum = 0;for (let i = 0; i < k; i++) {sum += nums[i] - avg;}if (sum >= 0) {return true;}let pre_sum = 0;let min_pre_sum = 0;for (let i = k; i < nums.length; i++) {sum += nums[i] - avg;pre_sum += nums[i - k] - avg;min_pre_sum = Math.min(pre_sum, min_pre_sum);if (sum - min_pre_sum >= 0) {return true;}}return false;
}// 用例1
console.log(getResult([1, 12, -5, -6, 50, 3], 4));
// 用例2
console.log(getResult([1, 12, -5, -6, 50, 3, 90, 80, -100], 4));

Java算法源码

public class Main {public static void main(String[] args) {//    int k = 4;//    int[] nums = {1, 12, -5, -6, 50, 3};int k = 4;int[] nums = {1, 12, -5, -6, 50, 3, 90, 80, -100};System.out.println(getResult(nums, k));}public static String getResult(int[] nums, int k) {double minAvg = Integer.MAX_VALUE;double maxAvg = Integer.MIN_VALUE;for (int num : nums) {minAvg = Math.min(num, minAvg);maxAvg = Math.max(num, maxAvg);}double diff = 1e-5;while (maxAvg - minAvg >= diff) {double midAvg = (minAvg + maxAvg) / 2;if (check(nums, k, midAvg)) {minAvg = midAvg;} else {maxAvg = midAvg;}}return String.format("%.2f", minAvg).toString();}public static boolean check(int[] nums, int k, double avg) {double sum = 0;for (int i = 0; i < k; i++) {sum += nums[i] - avg;}if (sum >= 0) return true;double preSum = 0;double minPreSum = 0;for (int i = k; i < nums.length; i++) {sum += nums[i] - avg;preSum += nums[i - k] - avg;minPreSum = Math.min(preSum, minPreSum);if (sum - minPreSum >= 0) {return true;}}return false;}
}

LeetCode - 644 子数组最大平均数 II相关推荐

  1. LeetCode 643. 子数组最大平均数 I

    1. 题目 给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数. 示例 1: 输入: [1,12,-5,-6,50,3], k = 4 输出: 12.75 解释: 最大平均 ...

  2. leetcode 643. 子数组最大平均数 I(滑动窗口)

    给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数. 示例: 输入:[1,12,-5,-6,50,3], k = 4 输出:12.75 解释:最大平均数 (12-5-6+5 ...

  3. [Leetcode] 643. 子数组最大平均数 I java

    给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数. 示例 1: 输入: [1,12,-5,-6,50,3], k = 4 输出: 12.75 解释: 最大平均数 (12- ...

  4. 【LeetCode】第643题——子数组最大平均数I(难度:简单)

    [LeetCode]第643题--子数组最大平均数I(难度:简单) 题目描述 解题思路 代码详解 注意点 题目描述 给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数. 示 ...

  5. Leetcode滑窗系列(java):643. 子数组最大平均数 I

    Leetcode滑窗系列(java):643. 子数组最大平均数 I(新手小白仅供参考) 题目来源 leetcode 题目描述 个人思路 创建一个滑窗,将其值的和作为作为判断基准 然后滑窗的左右边界各 ...

  6. 【LeetCode】643. 子数组最大平均数 I

    class Solution1 {/*643. 子数组最大平均数 I给你一个由 n 个元素组成的整数数组 nums 和一个整数 k .请你找出平均数最大且 长度为 k 的连续子数组,并输出该最大平均数 ...

  7. 【每日一题】 643. 子数组最大平均数 I

    [每日一题] 643. 子数组最大平均数 I 避免每日太过咸鱼,一天搞定一道LeetCode算法题 一.题目描述 难度: 简单 给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大 ...

  8. 643. 子数组最大平均数 I

    链接:643. 子数组最大平均数 I 题解:https://leetcode-cn.com/problems/maximum-average-subarray-i/solution/jing-dian ...

  9. 643、子数组最大平均数 I

    643.子数组最大平均数 I 题目: 给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数. 示例: 输入:[1,12,-5,-6,50,3], k = 4 输出:12.75 ...

最新文章

  1. 目标形体形状轮廓重建:ICCV2019论文解析
  2. [Beta]第二次 Scrum Meeting
  3. 李宏毅机器学习课程4~~~分类:概率生成模型
  4. java 代码同步_Java同步代码块 转
  5. 命令界面:使用Java中的动态API处理Redis
  6. B 站崩了,受害程序员聊聊
  7. 从卓越工程的角度看微软中国开发团队的成长 (一)
  8. 位运算 —— 一个数二进制形式尾端为 0 的个数
  9. JavaScript - 正则表达之二
  10. 关于"舆情监测"关键词在百度搜索中的相关数分析
  11. 用户场景法,设计测试用例
  12. 机载激光雷达原理与应用科普(七)
  13. 数据预测模型_如何根据已有数据得出预测模型?线性回归公式来帮你!
  14. [经验] 系统封装常见问题大总结(非官方)
  15. unity 裙子摆动_【Unity Shader】摇摆的小草——顶点动画
  16. C语言编程 | 转义字符
  17. Python读写Excel文件-1
  18. 【转载】R语言dplyr包学习笔记(吐血整理宇宙无敌详细版)
  19. 1577 例题3 数字转换(LOJ10155) 约数计算 树上最长链(两次找最大深度)
  20. Verilog设计(二):分频电路设计

热门文章

  1. 单精度浮点型(float)和双精度浮点型(double)的区别
  2. Mysql中自定义函数的创建和执行
  3. 安全测试简述/安全审计工具
  4. python中累加函数_对Python实现累加函数的方法详解
  5. 离散数学 群,环和域
  6. photoshop 裁剪_30种无需Photoshop即可在线裁剪和调整图像大小的工具
  7. 计算机专业研究生的英语复试
  8. 用python制作网盘_3分钟教你用python制作一个简单词云
  9. Spark --入门简介
  10. 什么是哈希冲突?如何解决?