713. Subarray Product Less Than K
Your are given an array of positive integers nums
.
Count and print the number of (contiguous) subarrays where the product of all the elements in the subarray is less than k
.
Example 1:
Input: nums = [10, 5, 2, 6], k = 100 Output: 8 Explanation: The 8 subarrays that have product less than 100 are: [10], [5], [2], [6], [10, 5], [5, 2], [2, 6], [5, 2, 6]. Note that [10, 5, 2] is not included as the product of 100 is not strictly less than k.
Note:
0 < nums.length <= 50000
.0 < nums[i] < 1000
.0 <= k < 10^6
.
1.解析
题目大意,求解乘积小于k的所有连续子序列的个数
2.分析
这道题还是比较容易看出来的,连续子序列,序列内的元素不要求顺序,完全符合滑动窗口的解法。我刚开始用的是子序列数组和(其实就是滑动窗口的一种类型),但比较难去除重复的情况。参考@Grandyang博主的思路,关键的部分还是在于解决重复情况的代码 res += i - left + 1,个人觉得还是蛮精辟的。left表示窗口的左边界,i表示当前序列的遍历位置,当窗口内的元素乘积大于或等于k时,滑动窗口的左边界;若乘积小于k,根据当前左边界计算窗口内的元素。这样就可以解决重复计算元素的问题。我之前处理的时候,是检测到当窗口内的元素乘积大于或等于k才计算窗口内的子序列个数,这样要考虑去重的问题。
例如: nums = [10,5,2,6,5,3,2], k = 100
当检测到 10 * 5 * 2 == 100,计算子窗口的序列个数:[10] [10, 5] [5] ------- 3 移动左边界为1
继续检测到 5 * 2 * 6 * 5 > 100,计算子窗口的序列个数:[5] [5,2] [2,6] ... ------- 6
可以看到:如果当检测到窗口内的乘积大于k时,在统计,就要考虑去重的问题。所以整体来说,@Grandyang博主解决的思路精辟之处就在于:无论是否检测到窗口内的乘积大于k,都统计子序列的个数,这样就可以解决去重的问题
class Solution {
public:
int numSubarrayProductLessThanK(vector<int>& nums, int k) {
if (k <= 1) return 0;
int left = 0, res = 0, n = nums.size();
int allProduct = 1;
for (int i = 0; i < n; ++i) {
allProduct *= nums[i];
while (allProduct >= k) allProduct /= nums[left++]; //滑动窗口左边界往右移动
res += i - left + 1; //统计当前窗口内的子串个数
}
return res;
}
};