📌  相关文章
📜  从给定数组中计数其乘积在给定范围内的对(1)

📅  最后修改于: 2023-12-03 15:36:20.038000             🧑  作者: Mango

从给定数组中计数其乘积在给定范围内的对
问题描述

给定一个正整数数组 nums 和两个整数 lower 和 upper 。计算在范围 [lower, upper] 内的个数,其中乘积包含在给定的数组中。

例如:

输入: nums = [1,2,3], lower = 0, upper = 3

输出: 4

解释: 可以得到如下乘积: [1], [2], [3], [2,3]

解决方案

思路

根据乘法原理,对于数组 nums 中的每一个数,都可以选择以其为起点,连续乘积的结果,即:

  • 如果当前乘积在区间 [lower, upper] 中,那么将计数器加一;
  • 如果当前乘积小于 lower,那么继续向右扩展窗口;
  • 如果当前乘积大于 upper,那么将左窗口往右移动一位,并缩小乘积。

用两个指针(left 和 right)记录区间的左右边界,一个变量(prod)记录区间内的乘积。

代码实现

class Solution:
    def countRangeSum(self, nums: List[int], lower: int, upper: int) -> int:
        def count(left, right):
            if left == right:
                return 0
            
            res = 0
            mid = (left + right) // 2
            
            res += count(left, mid) + count(mid + 1, right)
            
            i = left
            l = r = mid + 1
            
            while i <= mid:
                while l <= right and prefix_sum[l] - prefix_sum[i] < lower:
                    l += 1
                while r <= right and prefix_sum[r] - prefix_sum[i] <= upper:
                    r += 1
                res += r - l
                i += 1
            
            sorted_prefix_sum[left:right+1] = sorted(prefix_sum[left:right+1])
            return res
        
        prefix_sum = [0]
        for num in nums:
            prefix_sum.append(prefix_sum[-1] + num)
            
        sorted_prefix_sum = [0] * len(prefix_sum)
            
        return count(0, len(prefix_sum) - 1)  

复杂度分析

  • 时间复杂度:O(nlogn),其中 n 为 nums 的长度。这里的时间复杂度的来源有:

    • 用 O(n) 的时间复杂度递推出前缀和数组 prefix_sum,可以获得所有子区间的和;
    • 用 O(nlogn) 的时间复杂度对 prefix_sum 排序,以支持二分查找;
    • 用 O(nlogn) 的时间复杂度递归将数组二分,最后将结果进行归并。
  • 空间复杂度:O(n),即为前缀和数组 $\text{prefix_sum}$ 的长度。