LeetCode 乘积小于K的子数组(图解)

版权声明:本文为博主原创文章,博客地址:https://blog.csdn.net/qq_41855420,未经博主允许不得转载。 https://blog.csdn.net/qq_41855420/article/details/89597792

给定一个正整数数组 nums。

找出该数组内乘积小于 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的子数组。

说明:

0 < nums.length <= 50000
0 < nums[i] < 1000
0 <= k < 10^6

思路分析: 刚开始吧想着利用类似动态规划的思路,先确定子数组的尾端,然后一直往前扩展数组。蛋试题目的测试量有些大。。。
在这里插入图片描述

class Solution {
public:
	int numSubarrayProductLessThanK(vector<int>& nums, int k) {
		int numsSize = nums.size(), result = 0;
		for (int right = 0; right < numsSize; ++right) {//子数组以nums[right]为结尾
			int left = right, tempK = 1;
			while (left >= 0 && nums[left] * tempK < k) {//一直往前扩展子数组,直到出边界或者大小超过了K
				tempK *= nums[left--];
				result += 1;
			}
		}
		return result;
	}
};

不难发现,在确定left时存在大量的重复乘法计算,大大增加了运算量。那么我们能不能只计算一次呢?
下面对上面的思路进行优化,我们首先确定left = right = 0,tempK(子数组的乘积) = 1,一直扩充右边界right,直到tempK不小于k,这时以left为起始的子数组和的个数就是right - left,然后我们右移left,再次扩展right,又计算以当前left结尾的子数组个数…直到left走到了大数组的尾端。
在这里插入图片描述
在这里插入图片描述

class Solution {
public:
	int numSubarrayProductLessThanK(vector<int>& nums, int k) {
		int numsSize = nums.size(), result = 0;
        int left = 0, right = 0, tempK = 1;
        while (left < numsSize){
            //一直移动right,直到出界或者子数组乘积不小于k
            while (right < numsSize && tempK * nums[right] < k){
                tempK *= nums[right++];
            }
            if (right <= left){
                //此时是特殊情况,需要修正两个指针,比如[10, 5, 1], k = 5,出现了比k大的元素,此时right无法移动,需要矫正
                right = ++left;
                tempK = 1;
            }
            else{
                //计算以nums[left]为左边界的子数组个数
                result += (right - left);
                tempK /= nums[left++];//右移左边界,并且将nums[left]移出子数组的乘积
            }
        }
		return result;
	}
};

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41855420/article/details/89597792