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
題解分析
- 題目要求輸出爲:子數組的個數,子數組的元素是連續的,乘積小於且不等於 k
- 單個元素的數組也是允許的,但其值要小於 k
- 一種是先找出滿足調節的子數組,再統計數量;而是邊找邊統計,不需要維護子數組list
- 要點是找出所有的子數組,
- 依次遍歷,任一 i 的值小於 k, 則 count += 1
- 連續性判斷,如果 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