首先需要明确何时可以使用双指针法,一定是right向前移动时和或者时积要增大
思路:双指针
最主要的一点在于,当right移动后product仍然小于k时,此时的子数组的数目为right + left - 1
ex:nums = [10,5,1,6], k = 100
- 最初left = right = 0,此时有1个子数组[10];然后right=1,此时product<100,新增两个子数组[5],[10,5];然后right=2,此时仍有procudt<100,新增三个子数组[1],[5,1],[10,5,1]。也就是说如果最后product < 100,那么肯定会新增right-left+1个子数组
- 但是当product > 100时,我们需要用product/nums[left],然后left右移,直到product<100或者是left>right,那么如何判断最后是否会新增子数组呢?答案就是判断是否有right>=left
时空复杂度
- 时间复杂度:遍历一遍O(n)
- 空间复杂度:额外空间恒定O(1)
public int numSubarrayProductLessThanK(int[] nums, int k) {
int count = 0, left = 0, product = 1;
for (int right = 0; right < nums.length; right++) {
product *= nums[right];
while (product >= k && left <= right) {
product /= nums[left++];
}
count += right >= left ? right - left + 1 : 0;
}
return count;
}
Go代码
func numSubarrayProductLessThanK(nums []int, k int) int {
left, right, mul, result := 0, 0, 1, 0
for right < len(nums) {
mul *= nums[right]
for mul >= k && left <= right{
mul /= nums[left]
left++
}
result += right - left + 1
right++
}
return result
}
这道题的关键在于 right++ 后,新增的子数组个数为right-left+1,那么有几个子数组符合要求呢?答案是需要找到最小的left使得nums[left] * nums[left+1] … * nums[right] < target,这样符合条件的子数组的个数为right-left+1
还有一点需要注意的是,在找left的时候有可能不存在这样的子数组,所以内部循环需要增加一个条件就是left<=right(这是和前一道题不一样的地方)