「这是我参与2022首次更文挑战的第17天,活动详情查看:2022首次更文挑战」。
1.题目
乘积小于K的子数组
给定一个正整数数组 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的子数组。 示例 2:
输入: nums = [1,2,3], k = 0 输出: 0
提示:
1 <= nums.length <= 3 * 104 1 <= nums[i] <= 1000 0 <= k <= 106
思路
观察示例结果的输出,我们发现连续数组都是nums中的一个数连着它前面的数组成的;
即如果当前判断到数字6,则[6]、[2,6]、[5,2,6]是满足要求的,这个可以联想到数字6代表的是right,而5代表的 是left,如果考虑数字6,则以6结尾的满足小于k的连续子数组的个数就是right-left;
结合上面的分析,使用滑动窗口;
1:left是窗口的左界,right是窗口的右界;
2:使用product表示窗口的乘积,即left到right之间所有数的乘积,初始为1;
3:将product乘以right的数,并滑动right窗口;
4:如果当前product的值大于等于k,则除以left的值,并滑动left窗口;
5:此时product是满足小于k的条件,即窗口内的所有组合都是满足条件的,但是部分组合存在重复情况,只有以 right-1位置的值作为结尾的连续子数组故考虑则以right-1位置的值作为结尾的连续子数组的个数即为right-left。
1 <= nums.length <= 3 * 104
1 <= nums[i] <= 1000
0 <= k <= 106
代码
var numSubarrayProductLessThanK = function (nums, k) {
let left = 0;
let right = 0;
let len = nums.length;
let product = 1;
let count = 0;
//left是窗口的左界,right是窗口的右界
while (right < len) {
//使用product表示窗口的乘积,即left到right之间所有数的乘积,初始为1
product *= nums[right++];
while (product >= k && left < right) {
product /= nums[left++];
}
count += (right - left);
}
return count;
};