LeetCode 1343. 大小为 K 且平均值大于等于阈值的子数组数目

题目链接

1343. 大小为K且平均值大于等于阈值的子数组数目

题目描述

给你一个整数数组 arr 和两个整数 kthreshold,请你返回长度为 k 且平均值大于等于 threshold 的子数组数目。

解法分析:滑动窗口法

核心思路

该解法采用滑动窗口技术,通过维护一个长度为 k 的固定窗口,遍历数组时动态计算窗口内元素的和,并判断其平均值是否满足条件。具体步骤如下:

  1. 用滑动窗口遍历数组,窗口长度固定为 k
  2. 计算每个窗口的和,通过与 threshold * k 比较避免浮点数运算
  3. 统计满足条件的窗口数量

代码实现

class Solution:
    def numOfSubarrays(self, arr: List[int], k: int, threshold: int) -> int:
        l = ans = s = 0  # 左指针、结果计数、窗口和
        for r in range(len(arr)):
            s += arr[r]  # 累加当前元素到窗口和
            
            # 窗口长度不足k时跳过判断
            if r + 1 < k:
                continue
                
            # 判断窗口和是否≥threshold*k(等价于平均值≥threshold)
            if s >= threshold * k:
                ans += 1
                
            # 滑动窗口:减去左边界元素,左指针右移
            s -= arr[l]
            l += 1
            
        return ans

代码解析

  1. 初始化变量

    • l:滑动窗口左指针,初始为0
    • ans:满足条件的子数组数量,初始为0
    • s:当前窗口内元素的和,初始为0
  2. 遍历数组

    • 右指针 r 从0开始遍历每个元素
    • s += arr[r]:将当前元素累加到窗口和中
  3. 窗口判断逻辑

    • if r + 1 < k:当窗口长度不足k时(如前k-1个元素),跳过判断
    • if s >= threshold * k:窗口长度达到k时,通过和与threshold*k比较判断平均值是否达标
  4. 窗口滑动

    • s -= arr[l]:减去左边界元素,更新窗口和
    • l += 1:左指针右移,保持窗口长度为k

关键优化说明

  • 避免浮点数运算:通过 s >= threshold * k 替代 s/k >= threshold,避免浮点数除法,提升效率并避免精度问题
  • 固定窗口滑动:窗口长度始终为k,每次滑动仅需更新左边界元素,时间复杂度从O(n*k)优化到O(n)
  • 和的重用:利用前一个窗口的和,通过加减操作快速计算新窗口和,无需重复累加

复杂度分析

  • 时间复杂度:O(n),其中n为数组长度。每个元素被右指针访问1次,左指针最多移动n次,总操作次数为O(n)
  • 空间复杂度:O(1),仅使用常数级额外空间存储指针和临时变量

示例详解

以输入 arr = [2,2,2,2,5,5,5,8], k = 3, threshold = 4 为例:

  1. 初始化l=0, ans=0, s=0

  2. r=0,元素2

    • s = 0 + 2 = 2
    • r+1=1 < 3,跳过判断
  3. r=1,元素2

    • s = 2 + 2 = 4
    • r+1=2 < 3,跳过判断
  4. r=2,元素2

    • s = 4 + 2 = 6
    • r+1=3 >= 3,判断 6 >= 4*3=12?否,不计数
    • s = 6 - 2 = 4l=1
  5. r=3,元素2

    • s = 4 + 2 = 6
    • r+1=4 >= 3,判断 6 >= 12?否,不计数
    • s = 6 - 2 = 4l=2
  6. r=4,元素5

    • s = 4 + 5 = 9
    • r+1=5 >= 3,判断 9 >= 12?否,不计数
    • s = 9 - 2 = 7l=3
  7. r=5,元素5

    • s = 7 + 5 = 12
    • r+1=6 >= 3,判断 12 >= 12?是,ans=1
    • s = 12 - 2 = 10l=4
  8. r=6,元素5

    • s = 10 + 5 = 15
    • r+1=7 >= 3,判断 15 >= 12?是,ans=2
    • s = 15 - 5 = 10l=5
  9. r=7,元素8

    • s = 10 + 8 = 18
    • r+1=8 >= 3,判断 18 >= 12?是,ans=3
    • s = 18 - 5 = 13l=6
  10. 最终返回 3,即有3个满足条件的子数组。

总结

该解法通过滑动窗口技术高效解决了定长子数组平均值统计问题,核心优势在于:

  1. 线性时间复杂度:双指针移动确保每个元素仅被处理两次,适用于大规模数据
  2. 整数运算优化:通过和与阈值倍数比较,避免浮点数运算带来的精度问题和性能损耗
  3. 空间高效:仅使用常数级额外空间,满足内存限制要求

此方法适用于所有"定长子数组统计"场景,如子数组和、子数组最大值等问题,是滑动窗口技术的经典应用。在实际编程中,通过避免浮点数运算可以提升代码的运行效率和稳定性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值