Your are given an array of positive integers nums
.
Count and print the number of (contiguous) subarrays where the product of all the elements in the subarray is less than k
.
Example 1:
Input: nums = [10, 5, 2, 6], k = 100 Output: 8 Explanation: The 8 subarrays that have product less than 100 are: [10], [5], [2], [6], [10, 5], [5, 2], [2, 6], [5, 2, 6]. Note that [10, 5, 2] is not included as the product of 100 is not strictly less than k.
Note:
0 < nums.length <= 50000
.0 < nums[i] < 1000
.0 <= k < 10^6
.
這道題給了我們一個數組和一個數字K,讓求子數組且滿足乘積小於K的個數。既然是子數組,那么必須是連續的,所以肯定不能給數組排序了,這道題好在限定了輸入數字都是正數,能稍稍好做一點。博主剛開始用的是暴力搜索的方法來做的,就是遍歷所有的子數組算乘積和K比較,兩個 for 循環就行了,但是 OJ 不答應。於是上網搜大神們的解法,思路很贊。相當於是一種滑動窗口的解法,維護一個數字乘積剛好小於k的滑動窗口,用變量 left 來記錄其左邊界的位置,右邊界i就是當前遍歷到的位置。遍歷原數組,用 prod 乘上當前遍歷到的數字,然后進行 while 循環,如果 prod 大於等於k,則滑動窗口的左邊界需要向右移動一位,刪除最左邊的數字,那么少了一個數字,乘積就會改變,所以用 prod 除以最左邊的數字,然后左邊右移一位,即 left 自增1。當確定了窗口的大小后,就可以統計子數組的個數了,就是窗口的大小。為啥呢,比如 [5 2 6] 這個窗口,k還是 100,右邊界剛滑到6這個位置,這個窗口的大小就是包含6的子數組乘積小於k的個數,即 [6], [2 6], [5 2 6],正好是3個。所以窗口每次向右增加一個數字,然后左邊去掉需要去掉的數字后,窗口的大小就是新的子數組的個數,每次加到結果 res 中即可,參見代碼如下:
class Solution { public: int numSubarrayProductLessThanK(vector<int>& nums, int k) { if (k <= 1) return 0; int res = 0, prod = 1, left = 0; for (int i = 0; i < nums.size(); ++i) { prod *= nums[i]; while (left <= i && prod >= k) prod /= nums[left++]; res += i - left + 1; } return res; } };
討論:這道題其實可有很多種變形,比如當數組的數字有負數和0該怎么做?或者求的不是子數組,而是子序列該怎么做,子序列的話就可以排序啦,當然還是需要都是正數,才有排序的意義,博主覺得如果有負數和0,是不是只能暴力破解了,或者使用 Maximum Product Subarray 中的方法?再有一種的變形就是求子數組或子序列乘積剛好等於k,這就跟 Subarray Sum Equals K 和 Maximum Size Subarray Sum Equals k 這兩題中使用的方法類似吧,建立子數組和其乘積之間的映射來快速找到。
歡迎大家在評論區留言討論!
Github 同步地址:
https://github.com/grandyang/leetcode/issues/713
類似題目:
Maximum Size Subarray Sum Equals k
參考資料:
https://leetcode.com/problems/subarray-product-less-than-k/