713. 乘积小于 K 的子数组 滑动窗口

713. 乘积小于 K 的子数组

已解答

中等

相关标签

相关企业

提示

给你一个整数数组 nums 和一个整数 k ,请你返回子数组内所有元素的乘积严格小于 k 的连续子数组的数目。

示例 1:

输入:nums = [10,5,2,6], k = 100
输出:8
解释:8 个乘积小于 100 的子数组分别为:[10]、[5]、[2]、[6]、[10,5]、[5,2]、[2,6]、[5,2,6]。
需要注意的是 [10,5,2] 并不是乘积小于 100 的子数组。

示例 2:

输入:nums = [1,2,3], k = 0
输出:0

提示: 

  • 1 <= nums.length <= 3 * 104
  • 1 <= nums[i] <= 1000
  • 0 <= k <= 106

思路:

  1. 遍历列表:

    • 使用 for 循环遍历列表 numsr 依次指向列表中的每个元素。
    • 在每次循环中,将当前 r 指向的元素乘以 s,更新乘积。
  2. 调整窗口:

    • 当 s 大于等于 k 时,说明当前窗口的乘积不满足条件,需要缩小窗口。
    • 通过将 s 除以 l 指向的元素,并将 l 向右移动一位,来缩小窗口。
    • 这个过程一直持续到 s 小于 k 或者 l 与 r 相等。
  3. 计算结果:

    • 如果 s 小于 k,说明当前窗口的乘积满足条件。
    • 此时,以 r 为右边界的满足条件的子数组个数为 r - l + 1,将其加入 ans

当 s(窗口内元素乘积)小于 k 时,以 r 为右边界的满足条件的子数组个数为 r - l + 1,原因如下:

假设当前窗口的左右边界为 l 和 r

  1. 子数组的个数计算方式:

    • 从左边界 l 开始到右边界 r 的连续子数组,其个数可以通过数学方式来计算。
    • 以 l 为起点,长度为 1 的子数组有 1 个,即 nums[l:r+1](这里切片是从 l 到 r,包含 r)。
    • 以 l + 1 为起点,长度为 2 的子数组有 1 个,即 nums[l + 1:r + 1]
    • 以此类推,直到以 r 为起点,长度为 r - l + 1 的子数组有 1 个,即 nums[r:r + 1]
  2. 推导过程:

    • 对于一个长度为 n 的连续区间,它的子数组个数为 1 + 2 + 3 +... + n
    • 根据等差数列求和公式,这个和为 n*(n + 1)/2
    • 在这里,区间长度为 r - l + 1,所以子数组个数就是 (r - l + 1)*((r - l + 1) + 1)/2
    • 化简后得到 (r - l + 1)*(r - l + 2)/2
    • 但实际上,不需要进行这么复杂的计算,因为这里只需要知道子数组的总数,而总数就是从 l 到 r 的连续元素个数,即 r - l + 1

例如,当 l = 1r = 3 时,子数组有 nums[1:4](长度为 3)、nums[2:4](长度为 2)、nums[3:4](长度为 1),一共 3 - 1 + 1 = 3 个。

class Solution(object):
    def numSubarrayProductLessThanK(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        l=0
        s=1
        ans=0
        for r in range(len(nums)):
            s*=nums[r]
            while s>=k and l<r:
                s/=nums[l]
                l+=1
            if s<k:
                ans+=r-l+1
        return ans
            

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西柚与蓝莓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值