返回

O(nlogn) 求区间和的个数:算法巧思,代码简洁

前端

算法原理

我们知道,区间和 S(i, j) 等于 S(0, j) - S(0, i-1)。因此,我们可以预先计算出所有前缀和 S(0, i),然后利用二分查找来查找满足条件的区间个数。具体步骤如下:

  1. 计算所有前缀和 S(0, i) 并存储在数组 prefix_sum 中。
  2. 对于每个查询区间 [lower, upper],我们可以通过二分查找找到满足 S(0, j) ≥ upper 的最小索引 j 和满足 S(0, i) ≤ lower - 1 的最大索引 i。
  3. 那么,区间和在 [lower, upper] 之间的个数就是 j - i。

代码实现

def count_range_sum(nums, lower, upper):
    # 计算前缀和
    prefix_sum = [0]
    for num in nums:
        prefix_sum.append(prefix_sum[-1] + num)

    # 二分查找满足条件的区间个数
    count = 0
    for i in range(len(nums)):
        left, right = i, len(nums) - 1
        while left <= right:
            mid = (left + right) // 2
            if prefix_sum[mid] - prefix_sum[i] >= lower:
                right = mid - 1
            else:
                left = mid + 1
        count += left - i

    return count

# 测试用例
nums = [1, 2, 3, 4]
lower = 2
upper = 5
result = count_range_sum(nums, lower, upper)
print(f"区间和在 [{lower}, {upper}] 之间的个数为:{result}")

时间复杂度分析

计算前缀和的时间复杂度为 O(n),二分查找的时间复杂度为 O(nlogn),因此总的时间复杂度为 O(nlogn)。

结语

在这个问题中,我们利用二分查找的思想将算法复杂度从 O(n2) 优化到了 O(nlogn)。这个技巧在很多算法问题中都有应用,希望你能灵活运用它来解决更多难题。

参考文献