力扣 leetcode 713. 乘积小于 K 的子数组

问题描述

给你一个整数数组 nums 和一个整数 k ,请你返回子数组内所有元素的乘积严格小于 k 的连续子数组的数目。

提示:

1 <= nums.length <= 3 * 104
1 <= nums[i] <= 1000
0 <= k <= 106

示例

示例 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

解题思路

本题要计算乘积小于 k 的子数组个数,可以维持一个滑动窗口,利用滑动窗口计算子数组的个数。

首先,我们要找出子数组个数的规律。假设我们当前滑动窗口内有 n 个元素,新添加一个元素 x 后,子数组的个数增加 y 个,那么,如何计算这个 y 呢?具体分析如下:

  • x 可以单独组成一个子数组,y += 1
  • x 与 n - 1, n - 2, n - 3, ... , 0 组合成 [x, n - 1], [x, n - 1, n - 2], [x, n - 1, n - 2, n - 3], ... , [x, n - 1, n - 2, n - 3, ... , 0] 的子数组,这些子数组共有 n 个

因此,添加 x 后,y = n + 1。那么,如果我们移动滑动窗口,是否会造成重复计算呢?答案是否定的。我们移动滑动窗口后,再次统计子数组个数时,还是要将新的元素加入滑动窗口后才进行统计,而 y 表示的是一个新的元素加入后,子数组的新增个数,因此不会造成重复计算。

按照上述思路,我们实现以下代码:

class Solution {
public:
    int numSubarrayProductLessThanK(vector<int>& nums, int k) {
        int windowSize = 0;
        int cnt = 0;
        int sum = 1;
        for(int i = 0; i < nums.size(); i++){
            if(nums[i] >= k){ // 这里实际上只把开头的大于 k 的元素跳过
                continue;
            }
            for(int j = i + windowSize; j < nums.size(); j++){
                if(nums[j] < k){ // 判断 nums[j]是否大于k
                    sum *= nums[j];
                    windowSize++; // 将nums[j]加入滑动窗口
                    if(sum >= k){ // 判断当前滑动窗口内元素乘积是否大于k
                        int n = i;
                        for(; n < j; n++){ // 大于k 时,将滑动窗口内元素从前往后依次弹出,直到乘积小于k
                            sum /= nums[n];
                            windowSize--;
                            if(sum < k){
                                break;
                            }
                        }
                        i = n + 1;
                    }
                    cnt += windowSize; // 统计新增子数组个数
                }
                else{ // 发现大于k的元素,跳出循环,清空滑动窗口
                    sum = 1;
                    i = j;
                    windowSize = 0;
                    break;
                }
            }
        }
        return cnt;
    }
};
posted @ 2022-12-03 17:15  greatestchen  阅读(15)  评论(0编辑  收藏  举报