1 条题解

  • 0
    @ 2025-10-19 14:54:14

    题目题解:最大连续子序列平均值(长度至少为kk

    一、题目解析

    给定长度为 nn 的整数数组,需找到长度至少为 kk 的连续子序列,使得该子序列的平均值最大。

    • 直接暴力枚举所有长度≥kk 的子序列:时间复杂度为 O(n2)O(n^2),对于 nn 较大(如 10510^5 级别)的用例,会因超时无法通过。
    • 核心矛盾:需将“找最大平均值”的优化问题,转化为可高效判定的问题,降低时间复杂度。

    二、算法思路(二分查找 + 前缀和优化)

    1. 核心思想:二分查找转化判定问题

    最大平均值的取值范围是数组最小值 ~ 数组最大值(因为子序列平均值不会超出数组元素的取值区间)。利用二分查找逐步缩小这个范围,每次验证“当前候选平均值是否存在对应的合法子序列”。

    2. 关键步骤:判定候选平均值是否可行

    对于候选平均值 midmid,需判断:是否存在长度≥kk 的连续子序列,其平均值≥midmid

    • 转化子问题:若子序列 a[l..r]a[l..r](长度 rl+1kr-l+1 ≥k)的平均值≥midmid,则等价于:
      [ \frac{a[l] + a[l+1] + ... + a[r]}{r-l+1} ≥ mid ]
      两边同乘长度(正数,不改变不等号方向),整理得:
      [ (a[l] - mid) + (a[l+1] - mid) + ... + (a[r] - mid) ≥ 0 ]
      即:构造新数组 b[i]=a[i]midb[i] = a[i] - mid,问题转化为“是否存在长度≥kk 的连续子数组,使得 bb 的子数组和≥00”。

    3. 前缀和优化判定效率

    前缀和数组 ss 快速计算 bb 的子数组和:

    • 前缀和定义:s[0]=0s[0] = 0s[i]=b[1]+b[2]+...+b[i]s[i] = b[1] + b[2] + ... + b[i]
    • 子数组 b[j+1..i]b[j+1..i] 的和 = s[i]s[j]s[i] - s[j](需满足 ijki-j ≥k,即 jikj ≤ i-k)。

    为快速找到“是否存在 jikj ≤ i-k 使得 s[i]s[j]0s[i] - s[j] ≥0”,只需维护iki-k 个前缀和中的最小值 min_prefixmin\_prefix

    • s[i]min_prefix0s[i] - min\_prefix ≥0:说明存在 jj 满足条件,midmid 可行。
    • 否则:更新 min_prefixmin\_prefix(纳入新的前缀和 s[ik+1]s[i-k+1],为后续 ii 增大做准备)。

    三、算法流程总结

    1. 初始化二分区间:左边界 left=left = 数组最小值,右边界 right=right = 数组最大值。
    2. 二分迭代
      • 计算中间值 mid=(left+right)/2mid = (left + right) / 2
      • 调用判定函数,检查 midmid 是否可行。
      • 若可行:说明存在更大的平均值,将 left=midleft = mid(保留右半区间)。
      • 若不可行:说明平均值需更小,将 right=midright = mid(保留左半区间)。
    3. 终止条件:当 rightleft<EPSright - left < EPSEPSEPS 为精度阈值,如 1e61e-6),此时 leftleft(或 rightright)即为最大平均值。

    四、算法分析

    • 时间复杂度O(nlogMEPS)O(n \cdot \log \frac{M}{EPS})
      • nn 为数组长度,每次判定需遍历数组(O(n)O(n))。
      • 二分次数由 MM(数组最大值与最小值的差)和 EPSEPS 决定,通常迭代 3030~5050 次即可满足精度要求。
    • 空间复杂度O(n)O(n)(存储前缀和数组,可优化为 O(1)O(1),仅维护当前前缀和与最小前缀和)。

    五、算法标签

    • 二分查找
    • 前缀和
    • 子数组和问题
    • 优化判定(转化问题思想)
    • 1

    信息

    ID
    3334
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    14
    已通过
    1
    上传者