二十天刷题计划--滑动窗口(2)

283 阅读1分钟

「这是我参与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;
};