持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情
题目描述
给你一个整数数组 nums
和一个整数 k
,请你返回子数组内所有元素的乘积严格小于 k
的连续子数组的数目。
示例
输入: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 的子数组。
输入: nums = [1,2,3], k = 0
输出: 0
提示
1 <= nums.length <= 3 * 10^4
1 <= nums[i] <= 1000
0 <= k <= 10^6
滑动窗口
这道题要求的是连续的子数组且乘积严格小于目标值k
,那么我们可以使用滑动窗口的方式,不断的累积乘积,直至其超过目标值,再移动左边界,重复前面的步骤。长度的计算可以通过右边界减去左边界来求得区间长度。
class Solution {
public int numSubarrayProductLessThanK(int[] nums, int k) {
// 边界判断
if(k == 0){
return k;
}
// 初始化
int n = nums.length, res = 0;
int tmp = 1;
// 双指针滑动窗口
for(int i = 0, j = 0; j < n; ++j){
// 区间求积
tmp *= nums[j];
// 当结果大于k,则左边界右移
while(i <= j && tmp >= k){
tmp /= nums[i++];
}
// 累加区间长度
res += j - i + 1;
}
// 返回结果
return res;
}
}
滑动窗口模版
public void method(int[] arr){
// 边界指针
int left = 0, right = 0;
int res = 0, len = 0;
while(right < arr.length){
// 先移动右边的指针,累加元素之类的操作
res += arr[right++];
// 判断是否超过条件
while(left < right && res < targer){
// 超过的话则左边界移动
res -= arr[left++];
}
// 区间长度
len += right - left + 1;
}
}
复杂度分析
-
时间复杂度:
O(n)
,其中n
是数组 的长度。两个端点i
和j
的增加次数都不超过n
。 -
空间复杂度:
O(1)
。