当前位置 博文首页 > 布谷鸟:算法练习:乘积小于K的子数组

    布谷鸟:算法练习:乘积小于K的子数组

    作者:[db:作者] 时间:2021-09-03 15:10

    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
    
    
    cs