滑动窗口

167 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第17天,点击查看活动详情

滑动窗口

题干

给定一个正整数数组 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的子数组。

介绍:

滑动窗口法可以用来解决一些查找满足一定条件的连续区间的性质(长度等)问题。通过移动两个下标或指针。来查找满足条件的区间。

题目分析,解题思路

需要一个数记录当前子数组最大乘积。我们用maxnum。满足条件的子数组数ans

初始时:两个指针都在下标0的位置

此时maxnum = nums[0],maxnum < k,

满足条件的子数组数ans = 1.

右指针右移一位: 左指针下标0,右指针下标1

此时maxnum *= nums[1],maxnum < k

满足条件的子数组数有前面的一个,加上(当前数)+ 家当前数乘以上一位数(num[0]*num[1]):3个

满足条件的子数组数`ans = 3。

右指针右移一位 :左指针下标0,右指针下标2

此时maxnum *= nums[2],maxnum > k。大于k了,说明这个区间不能满足要求。

把左指针右移一位,在这之前最大值也要除去移出的哪一位,即maxnum / nums[1]。表示区间缩小了一位。区间数为[5,2],那么到2为止,满足条件的子数字有,前面算出的,加上区间长度2。

满足条件的子数组数`ans = 3+2=5。

......

为什么满足条件的子数组数等于区间长度?

无论区间多长,我们每次遍历都是新加一位新元素。如果说区间[5,2,6]是满足条件的,第三位元素是遍历加入的,新元素前的每一个元素都以计算过一遍了。区间满足条件,那么能新加的子数组个数就是:新数组与区间前面每个元素的组合。就刚好是等于数组长度。

代码实现

func subArrayNums(nums []int, k int) int {
    if k<=1{
        return 0
    }
    now,l,r,ans:=1,0,0,0
    for r<len(nums){
        now*=nums[r]
        for now>=k{
            now/=nums[l]
            l++
        }
        ans+=r-l+1
        r++
    }
    return ans
}