1. 程式人生 > >[LeetCode] Subarray Product Less Than K 子陣列乘積小於K

[LeetCode] Subarray Product Less Than K 子陣列乘積小於K

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 (prod >= k) prod /= nums[left++];
            res 
+= i - left + 1; } return res; } };

討論:這道題其實可有很多種變形,比如當陣列的數字有負數和0該怎麼做?或者求的不是子陣列,而是子序列該怎麼做,子序列的話就可以排序啦,當然還是需要都是正數,才有排序的意義,博主覺得如果有負數和0,是不是隻能暴力破解了,或者使用Maximum Product Subarray中的方法?再有一種的變形就是求子陣列或子序列乘積剛好等於k,這就跟Subarray Sum Equals KMaximum Size Subarray Sum Equals k這兩題中使用的方法類似吧,建立子陣列和其乘積之間的對映來快速找到。

歡迎大家在評論區留言討論!

類似題目:

參考資料: