掌握 Java 滑动窗口:「滑动窗口的平均值」计算与代码实现细节

引言

滑动窗口算法是一种处理连续数据子集的强大工具,广泛应用于实时数据分析、信号处理和算法优化中。在 Java 中,掌握这一技术能帮助开发者高效解决数组或序列上的连续统计问题。本文将聚焦于“滑动窗口的平均值”计算,通过清晰的结构逐步讲解算法原理、Java 实现细节和关键优化点,确保内容原创且实用。文章不涉及任何无关技术或术语,专注于 Java 核心知识。

问题描述

给定一个长度为 $n$ 的整数数组 $\text{nums}$ 和一个窗口大小 $k$($1 \leq k \leq n$),计算每个连续窗口的平均值。窗口从数组起始位置滑动到末尾,每个窗口包含 $k$ 个元素。例如:

  • 输入:$\text{nums} = [1, 2, 3, 4, 5]$, $k = 3$
  • 输出:平均值数组 $[2.0, 3.0, 4.0]$,对应窗口 $[1,2,3]$, $[2,3,4]$, $[3,4,5]$

数学上,每个窗口的平均值定义为: $$\text{平均值} = \frac{\sum_{i=\text{start}}^{\text{end}} \text{nums}[i]}{k}$$ 其中 $\text{start}$ 和 $\text{end}$ 是窗口的起始和结束索引。

算法思路

核心思想是避免重复计算每个窗口的总和,通过动态维护窗口总和来提升效率。步骤如下:

  1. 初始化:计算第一个窗口的总和。
  2. 滑动窗口:移动窗口时,添加新元素并移除旧元素,更新总和。
  3. 计算平均值:每个位置使用当前总和除以 $k$。
  4. 边界处理:当窗口大小 $k$ 无效时,返回空数组。

时间复杂度为 $O(n)$($n$ 是数组长度),空间复杂度为 $O(1)$(额外空间仅用于变量),优于暴力方法的 $O(n \times k)$。

Java 代码实现

以下是完整 Java 代码,包含详细注释。代码使用标准 Java 语法,确保可读性和可靠性。

/**
 * 计算滑动窗口平均值
 * @param nums 输入数组,长度 n >= 1
 * @param k 窗口大小,1 <= k <= n
 * @return 包含每个窗口平均值的数组
 */
public double[] movingAverage(int[] nums, int k) {
    // 检查无效输入:k 超出范围时返回空数组
    if (k <= 0 || k > nums.length) {
        return new double[0];
    }
    
    int n = nums.length;
    double[] result = new double[n - k + 1]; // 结果数组长度
    double windowSum = 0; // 窗口总和
    
    // 初始化第一个窗口的总和
    for (int i = 0; i < k; i++) {
        windowSum += nums[i];
    }
    result[0] = windowSum / k; // 第一个窗口的平均值
    
    // 滑动窗口:从索引 k 开始
    for (int i = k; i < n; i++) {
        // 添加新元素,移除旧元素(索引 i - k)
        windowSum += nums[i] - nums[i - k];
        result[i - k + 1] = windowSum / k; // 计算并存储平均值
    }
    
    return result;
}

实现细节分析
  1. 边界处理

    • 在方法开头检查 $k$ 的有效性,防止数组越界错误。
    • 当 $k = 1$ 或 $k = n$ 时,代码仍能正确处理(例如 $k = n$ 时返回一个平均值)。
  2. 效率优化

    • 使用单变量 windowSum 动态更新总和,避免每次重新计算,确保 $O(n)$ 时间复杂度。
    • 结果数组长度精确为 $n - k + 1$,减少空间浪费。
  3. 数值精度

    • 平均值使用 double 类型存储,避免整数除法导致的精度损失。
    • 在累加时处理大数溢出问题(Java 的 double 能处理常见范围)。
  4. 测试建议

    • 单元测试用例:
      • 基础测试:$\text{nums} = [1, 2, 3, 4, 5]$, $k = 3$ → $[2.0, 3.0, 4.0]$
      • 边界测试:$k = 1$ → 每个元素单独平均值;$k = n$ → 单个平均值。
      • 无效输入:$k = 0$ 或 $k > n$ → 返回空数组。
应用场景与总结

滑动窗口平均值算法在实时监控系统(如股票价格分析)和数据处理流水线中极为实用。通过本文:

  • 你掌握了算法核心:动态维护总和以提升性能。
  • Java 实现强调代码健壮性,如输入验证和类型处理。
  • 进一步练习:尝试扩展为加权平均值或处理流数据。

通过逐步实现和细节讨论,你可在实际项目中快速集成此算法,提升 Java 开发技能。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐