乘积小于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

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/subarray-product-less-than-k
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路

我的思路,嗯其实双指针和滑动窗口是差不多的呀,有些时候以滑动窗口理解双指针会更好理解。首先来考虑朴素的做法:使用双重循环遍历所有子数组,计算子数组的乘积是否符合条件。时间复杂度是O(n2)。朴素的做法时间复杂度较高的原因在于使用了双重循环,假设外层循环的index为i,内层循环的index为j,每次外层循环时j都会回溯导致时间复杂度较高。那么如何能够使得j不回溯呢?遍历每个一个i开头的子数组并且计算以i开头的子数组符合条件的数目,我们需要找到恰好符合条件的[i,j]使得其乘积恰好小于k,那么以i开头的子数组的数目为j-i+1;当计算i+1开头的子数组数目时并不需要j回溯,将i移除之后[i+1,j]的乘积是必然符合条件的也就是利用了之前的计算结果使得j不需要回溯,只需要将j不断后移,直到找到[i+1,j]使得乘积恰好小于k即可。思路就是这么一个思路,实现上还是有一点细节的,比如nums[i] >= k,那么i开头的子数组都是不可能符合条件的,直接跳过即可;当j == nums.size() -1也就是末尾时,这是i及i往后的所有子数组都是符合条件的,直接计算数目并退出即可。

代码

class Solution {
public:
    //朴素做法时间复杂度在于j每次都要回溯
    //j不回溯
    //遍历每一个i开始的子数组符合条件的数目
    //找到恰好没有超出k的[i,j],那么从i开始的子数组数目为j-i+1
    //i+1,继续寻找恰好没有超出k的[i+1,j]并计算数目
    //j不需要回溯
    
    int numSubarrayProductLessThanK(vector<int>& nums, int k) {

        int ans = 0;

        int i = 0,j = 0;

        int mul = nums[0];
        while(i < nums.size())
        {
            //如果i>=k,那么不可能有i开始的字符串
            //直接跳过即可
            if(nums[i] >= k)
            {
                i = i +1;
                j = i;
                mul = nums[i];
            }
            //判断从i开始能走多远
            while(j < nums.size() && mul < k)
            {
                
                j++;
                if(j < nums.size()) mul = mul * nums[j]; 
            }
            //cout<<i<<" "<<j<<endl;

            //如果还是小于k,也就是i以及i往后的所有都是小于k的
            //直接计算结果就行
            if(mul < k)
            { 
                ans += (j - i) * (j - i +1) / 2;
                break;
            }
            //否则i最远能够到[i,j-1],以i开始的数组有j-i个
            else 
            {
                ans += j -i;
                mul = mul / nums[i];
                i++;
            }
        }

        return ans;
    }
};
posted on   huangxk23  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示