算法練習每日一題:乘積小於K的子數組

713. 乘積小於K的子數組

給定一個正整數數組 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

鏈接:https://leetcode-cn.com/problems/subarray-product-less-than-k

題解分析

  1. 題目要求輸出爲:子數組的個數,子數組的元素是連續的,乘積小於且不等於 k
  2. 單個元素的數組也是允許的,但其值要小於 k
  3. 一種是先找出滿足調節的子數組,再統計數量;而是邊找邊統計,不需要維護子數組list
  • 要點是找出所有的子數組,
    1. 依次遍歷,任一 i 的值小於 k, 則 count += 1
    2. 連續性判斷,如果 j = i,j < n,l[i:j]乘積小於 k ,則 count += 1;如果大於等於 k, 則 i += 1,i 向右移動
# 該方法提示超時

class Solution:
    def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int:
        if not nums:
            return None
        count = 0 
        length = len(nums)
        for i in range(0,length):
            if nums[i] < k:
                count += 1
            j = i + 1
            mult = nums[i]
            while j < length:
                mult *= nums[j]
                if mult < k:
                    count += 1
                    j += 1
                else:
                    break
        return count

方法二:雙指針

  • 分析

我們可以使用二分查找解決這道題目,即對於固定的 i,二分查找出最大的 j 滿足 nums[i] 到 nums[j] 的乘積小於 k。但由於乘積可能會非常大(在最壞情況下會達到 1000^50000,會導致數值溢出,因此我們需要對 nums 數組取對數,將乘法轉換爲加法,即 log⁡(∏inums[i])=∑ilog⁡ nums[i],這樣就不會出現數值溢出的問題了。

  • 算法

對 nums 中的每個數取對數後,我們存儲它的前綴和 prefix,即 prefix[i+1]=∑nums[x],這樣在二分查找時,對於 i 和 j,我們可以用 prefix[j+1]−prefix[i] 得到 nums[i] 到 nums[j] 的乘積的對數。對於固定的 i,當找到最大的滿足條件的 j 後,它會包含 j−i+1 個乘積小於 k 的連續子數組。

# 現在提交也是超時
class Solution:
    def numSubarrayProductLessThanK(self, nums, k):
            if k <= 1: return 0
            mult = 1
            count = left = 0
            for right, val in enumerate(nums):
                mult *= val
                while mult >= k:
                    mult /= nums[left]
                    left += 1
                count += right - left + 1
            return count

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章