leetcode1343:大小为K的子数组(定长滑动窗口)

文章目录

  • [一、 题目描述](#一、 题目描述)
  • [二、 核心思路 - 从"平均值"到"总和"的转换](#二、 核心思路 - 从“平均值”到“总和”的转换)
  • [三、 算法步骤](#三、 算法步骤)
  • [四、 代码实现与注释](#四、 代码实现与注释)
  • [五、 关键点与复杂度分析](#五、 关键点与复杂度分析)
  • [六、 两题对比:LC1052,LC1343](#六、 两题对比:LC1052,LC1343)

LeetCode 1343 - 大小为 K 且平均值大于等于阈值的子数组数目,【难度:中等;通过率:71.2%】,上一题的" LeetCode 1052 (爱生气的书店老板) "是利用滑动窗口求最值,而本例是利用滑动窗口统计数目,它要求我们统计一个数组中,所有满足特定条件的、固定大小的 子数组 的数量。这再次展示了滑动窗口算法在处理此类问题上的高效性

一、 题目描述

给你一个整数数组 arr 和两个整数 kthreshold

请你返回长度为 k 且平均值大于等于 threshold (阈值)的子数组数目

示例:

复制代码
输入:arr = [2,2,2,2,5,5,5,8], k = 3, threshold = 4
输出:3
解释:
子数组 [2,5,5] 的平均值为 (2+5+5)/3 = 4
子数组 [5,5,5] 的平均值为 (5+5+5)/3 = 5
子数组 [5,5,8] 的平均值为 (5+5+8)/3 = 6

输入:arr = [11,13,17,23,29,31,7,5,2,3], k = 3, threshold = 5
输出:6

二、 核心思路 - 从"平均值"到"总和"的转换

题目的条件是"平均值大于等于 threshold"。即:

(arr[i] + ... + arr[i+k-1]) / k >= threshold

直接处理浮点数除法可能会引入精度问题,而且效率不高。我们可以对这个不等式进行一个简单的数学转换:

(arr[i] + ... + arr[i+k-1]) >= threshold * k

这样,问题就从"判断子数组的平均值"转换为了"判断子数组的总和 "。我们只需要找到所有长度为 k 的子数组,计算它们的总和,并判断这个总和是否大于等于 threshold * k 即可

这个问题------"遍历所有固定长度的子数组并计算其总和"------正是滑动窗口算法的完美应用场景


三、 算法步骤

  1. 计算目标和 :首先计算出子数组需要达到的最小总和 targetSum = threshold * k
  2. 初始化窗口 :计算第一个窗口(即数组的前 k 个元素)的总和 windowSum
  3. 判断第一个窗口 :检查 windowSum 是否大于等于 targetSum。如果是,则计数器 count 加 1
  4. 滑动窗口
    • 从第 k 个元素开始,向右滑动窗口直到数组末尾
    • 窗口右移 :每次循环,窗口向右移动一格。新的元素 arr[i] 进入窗口,所以 windowSum += arr[i]
    • 窗口左移 :同时,旧的元素 arr[i - k] 离开了窗口,所以 windowSum -= arr[i - k]
    • 判断新窗口 :每次更新 windowSum 后,都检查它是否大于等于 targetSum。如果是,则 count 加 1
  5. 返回结果 :循环结束后,返回最终的 count

四、 代码实现与注释

java 复制代码
class Solution {
    public int numOfSubarrays(int[] arr, int k, int threshold) {
        // len: 数组的长度
        // l:   滑动窗口的左边界
        // ans: 存储满足条件的子数组的数量
        // sum: 存储当前滑动窗口内元素的总和
        int len = arr.length, l = 0, ans = 0, sum = 0;

        // 步骤 1: 初始化第一个窗口 (即索引从 0 到 k-1 的子数组)
        // 计算这个初始窗口内所有元素的总和
        for (int i = 0; i < k; i++) {
            sum += arr[i];
        }

        // 步骤 2: 判断第一个窗口是否满足条件
        // 如果当前窗口的平均值 (sum / k) 大于等于 threshold,则 ans 加 1,否则 ans 保持 0
        ans = sum / k >= threshold ? 1 : 0;

        // 步骤 3: 滑动窗口
        // r: 滑动窗口的右边界,从 k 开始遍历到数组末尾
        // 每次循环,窗口向右移动一格
        for (int r = k; r < arr.length; r++) {
            // 窗口左移:减去滑出窗口的元素 (arr[l])
            // l++ 使左边界向右移动一格,为下一次循环做准备
            sum -= arr[l++];
            
            // 窗口右移:加上新进入窗口的元素 (arr[r])
            sum += arr[r];

            // 判断当前新的窗口是否满足条件
            // 如果平均值 (sum / k) 大于等于 threshold,则 ans 加 1,否则 ans 保持不变
            ans = sum / k >= threshold ? ans + 1 : ans;
        }

        // 返回最终统计到的满足条件的子数组数量
        return ans;
    }

运行结果:


五、 关键点与复杂度分析

  • 问题转换:将"平均值"问题转换为"总和"问题是解题的第一步,这避免了浮点数运算,简化了逻辑
  • 滑动窗口模板:该解法是滑动窗口的标准模板应用。通过 O(1) 的更新操作(一加一减)来维护窗口的总和,从而高效地遍历所有固定大小的子数组
  • 数据类型 :使用 long 来存储 targetSumwindowSum 是一个很好的编程习惯,可以防止当 kthreshold 或数组元素较大时可能发生的整数溢出
  • 时间复杂度O(N)。我们只需要对数组进行一次遍历来构建和滑动窗口
  • 空间复杂度O(1)。我们只使用了常数个额外变量,与输入数组的规模无关

六、 两题对比:LC1052,LC1343

这两道题都是滑动窗口的经典应用,但它们在细节和目标上有所不同,通过对比可以加深我们对滑动窗口思想的理解

LeetCode 1052 (爱生气的书店老板) LeetCode 1343 (大小为 K 的子数组)
问题目标 求最值 - 找到一个窗口,使其"收益"最大。 计数 - 统计所有满足条件的窗口的数量。
问题分解 需要 - 分解为"基础满意度"和"额外收益"两部分。 不需要 (或说很简单) - 直接处理整个数组即可。
数据预处理 需要 - 将 grumpy 数组的 0/1 状态转化为实际的"可挽回顾客数"。 需要 - 将"平均值"条件转换为"总和"条件。
窗口内的计算 计算窗口内 grumpy[i]==1customers[i]总和 计算窗口内所有 arr[i]总和
核心逻辑 维护一个 maxIncrease 变量,在每次窗口滑动后 Math.max() 更新。 维护一个 count 变量,在每次窗口滑动后 if 判断并累加。
共同点 - 都处理固定大小 (kminutes) 的连续子数组。 - 都使用滑动窗口将时间复杂度优化到 O(N)。 - 空间复杂度都为 O(1)。

总结:

  • LC1052 (爱生气的书店老板) 更侧重于优化和求最值 。它需要你找到那一个能带来最大改变的窗口

  • LC1343 (大小为 K 的子数组) 更侧重于统计和计数 。它需要你检查每一个窗口是否满足条件

尽管目标不同,但解决它们的核心工具都是滑动窗口。通过这两道题的练习,我们可以看到滑动窗口思想的灵活性:它既可以用来寻找最优的子数组,也可以用来统计所有满足条件的子数组

相关推荐
运维帮手大橙子16 分钟前
完整的登陆学生管理系统(配置数据库)
java·前端·数据库·eclipse·intellij-idea
王大锤·26 分钟前
基于spring boot的个人博客系统
java·spring boot·后端
金智维科技官方1 小时前
常见的大模型分类
人工智能·算法·ai·语言模型·数据挖掘
yzzzzzzzzzzzzzzzzz1 小时前
leetcode热题——有效的括号
算法·
sg_knight1 小时前
Spring Cloud Gateway全栈实践:动态路由能力与WebFlux深度整合
java·spring boot·网关·spring·spring cloud·微服务·gateway
JosieBook1 小时前
【IDEA】IntelliJ IDEA 中文官方文档全面介绍与总结
java·ide·intellij-idea
三只蛋黄派1 小时前
Websocket
java
JIngJaneIL2 小时前
专利服务系统平台|个人专利服务系统|基于java和小程序的专利服务系统设计与实现(源码+数据库+文档)
java·数据库·小程序·论文·毕设·专利服务系统平台
freed_Day2 小时前
Java学习进阶--集合体系结构
java·开发语言·学习