LeetCode 分类刷题:713. 乘积小于 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
解析
注意数据范围 nums[i]≥1,所以乘积不可能小于 1。因此,当 k≤1 时,没有这样的子数组,直接返回 0。
由于子数组越长,乘积越大,越不能满足题目要求;反之,子数组越短,乘积越小,越能满足题目要求。有这种性质的题目,可以用滑动窗口解决。
枚举子数组右端点 right,如果发现子数组不满足要求,就缩小窗口,也就是增大左端点 left。
内层循环结束后,[left,right] 这个子数组是满足题目要求的。由于子数组越短,越能满足题目要求,所以除了 [left,right],还有 [left+1,right],[left+2,right],…,[right,right] 都是满足要求的。也就是说,当右端点固定在 right 时,左端点在 left,left+1,left+2,…,right 的所有子数组都是满足要求的,这一共有 right−left+1 个,加到答案中。
--------------------------------------------------------------------------------------------------------------------
作者:灵茶山艾府
链接:https://leetcode.cn/problems/subarray-product-less-than-k/solutions/1959538/xia-biao-zong-suan-cuo-qing-kan-zhe-by-e-jebq/
来源:力扣(LeetCode)
答案
/*** @param {number[]} nums* @param {number} k* @return {number}*/
var numSubarrayProductLessThanK = function(nums, k) {if(k <= 1) return 0;let left = 0, pro = 1, ans = 0; //初始化滑动窗口左指针,记录乘积和答案的变量for(let right = 0; right < nums.length; right++) { //右指针,用于扩大窗口pro *= nums[right]; //更新子数组乘积while(pro >= k) { //不满足乘积严格小于kpro /= nums[left];left++; //缩小窗口}ans += right - left + 1; //对于固定的right,有(right-left+1)个合法的左端点}return ans;
};
复杂度分析
时间复杂度:O(n),其中 n 为 nums 的长度。虽然写了个二重循环,但是内层循环中对 left 加一的总执行次数不会超过 n 次,所以总的时间复杂度为 O(n)。
空间复杂度:O(1),仅用到若干额外变量。作者:灵茶山艾府
链接:https://leetcode.cn/problems/subarray-product-less-than-k/solutions/1959538/xia-biao-zong-suan-cuo-qing-kan-zhe-by-e-jebq/
来源:力扣(LeetCode)。