我们先从数据量来分析,这题的数组长度nums.size()最长有3e4,这说明了用时间复杂度为n平方的算法肯定会爆,最多只能用nlogn的算法才行。
这题我们很容易想到用n平方遍历来写,直接暴力得答案的路肯定是行不通了,这题是连续子数组,我想到用滑动窗口的方法来写,但这题用一周双指针的解法会更加方便。先上代码:
class Solution {
public:
int numSubarrayProductLessThanK(vector<int>& nums, int k)
{
if (k <= 1) return 0;
int n = nums.size();
int ans = 0;
int temp = 1;
for(int i = 0,j = 0;i < n;i ++)
{
temp *= nums[i];
while(temp >= k && j <= i) temp /= nums[j++];
ans += i - j + 1;
}
return ans;
}
};
首先先是特判啦,k <= 1 就直接return 0 这没啥好说的。
核心的代码,就是 ans+= i - j + 1这行代码,先来解释一下为什么i - j + 1的数量是这期间的子数组的数量,然后ans可以直接加上去。
举个例子,拿例1的数据来看,10,5,2,6,k = 100。第一次遍历,10,很明显temp小于k,ans += 1,再继续,5,temp = 50 小于 100,ans += 2,以此类推,我们可以得到结论,如果一个连续数组里的数字的乘积小于k,那么这个数组的子数组都满足于小于k(因为这里面的num[i] 都大于0),我们在遍历一个数组的时候,从一步步进入这个数组到一步步退出这个数组,不断的i - j + 1的统计,是不是就统计了这个数组的所有子数组呢?不妨可以多用几组数组来测试一下,从进入到退出这其中不断的i - j + 1就可以统计完一个连续数组里所有的子数组了,我们只需要不断的滑动这个窗口就好了,缩到最小,放到最大,每个数组元素最多被遍历2次,时间复杂度可以算是。。O(n)?(我不太会算时间复杂度,小白一个),这就是我这题的思路