Skip to main content

327.区间和的个数

标签: array, binary-search, divide-and-conquer

难度: Hard

通过率: 36.35%

原题链接: https://leetcode.com/problems/count-of-range-sum/description/

题目描述

给定一个整数数组 nums 和两个整数 lowerupper ,返回位于 [lower, upper] 间的区间和的数量。区间和 S(i,j)S(i, j) 被定义为数组 nums 中下标 ij 之间元素的总和,包含 ij

解题思路

解决这个问题的关键在于如何在 O(nlogn)O(n \log n) 的时间复杂度内计算所有符合条件的区间和。由于直接暴力计算所有可能的区间和会导致 O(n2)O(n^2) 的时间复杂度,因此需要更有效的方法。我们可以通过以下方式来解决:

  1. 前缀和:初始化一个前缀和数组 prefix_sums ,其中 prefix_sums[i]nums[0]nums[i-1] 的和。
  2. 归并排序与二分搜索:在归并排序的过程中维持一个有序的前缀和数组。
  3. 对于每个元素prefix_sums[j],我们需要寻找有多少个 i < j 使得 lower <= prefix_sums[j] - prefix_sums[i] <= upper
  4. 通过用排序算法维护的有序数组来快速统计满足条件的区间和的数量,这是通过在进行 merge 时利用二分搜索来实现的。

代码实现

def countRangeSum(nums, lower, upper):
def merge_sort(lo, hi):
if hi - lo <= 1: # 若区间中只有一个元素
return 0 # 区间无法形成两点的区间和

mid = (lo + hi) // 2
count = merge_sort(lo, mid) + merge_sort(mid, hi) # 分治递归求解
j = k = t = mid
temp = []
for i in range(lo, mid):
while k < hi and prefix_sums[k] - prefix_sums[i] < lower: # 找到第一个满足条件的 k
k += 1
while j < hi and prefix_sums[j] - prefix_sums[i] <= upper: # 找到第一个不满足条件的 j
j += 1
count += j - k # 在范围中的[j:j)
while t < hi and prefix_sums[t] < prefix_sums[i]:
temp.append(prefix_sums[t]) # 归并排序
t += 1
temp.append(prefix_sums[i])
prefix_sums[lo:lo + len(temp)] = temp
return count

prefix_sums = [0]
for num in nums:
prefix_sums.append(prefix_sums[-1] + num) # 构建前缀和数组

return merge_sort(0, len(prefix_sums))

复杂度分析

时间复杂度为 O(nlogn)O(n \log n),其中 nn 是数组 nums 的长度。算法的主要复杂度来自于归并排序阶段,该阶段涉及分割和归并过程中进行二分查找来计算有效的范围和数量。

空间复杂度为 O(n)O(n),用于存储中间的前缀和数组以及合并排序中的辅助数组。