返回
O(nlogn) 求区间和的个数:算法巧思,代码简洁
前端
2024-01-06 20:03:49
算法原理
我们知道,区间和 S(i, j) 等于 S(0, j) - S(0, i-1)。因此,我们可以预先计算出所有前缀和 S(0, i),然后利用二分查找来查找满足条件的区间个数。具体步骤如下:
- 计算所有前缀和 S(0, i) 并存储在数组 prefix_sum 中。
- 对于每个查询区间 [lower, upper],我们可以通过二分查找找到满足 S(0, j) ≥ upper 的最小索引 j 和满足 S(0, i) ≤ lower - 1 的最大索引 i。
- 那么,区间和在 [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)。这个技巧在很多算法问题中都有应用,希望你能灵活运用它来解决更多难题。
参考文献