一起养成写作习惯!这是我参与「掘金日新计划 · 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
}