该题解采用分治法与归并排序的思想来解决问题。首先,我们计算了数组的前缀和,然后通过递归分治方法处理每个子数组,并在合并的过程中统计符合条件的区间和的个数。具体步骤如下:
1. 计算数组的前缀和,以便快速计算任意子数组的和。
2. 使用递归分治的方法来处理和合并子数组。对于每个子问题,如果它只包含一个元素,直接判断这个单独元素形成的区间和是否在指定范围内。
3. 在合并两个已经排序的子数组的过程中,使用双指针技术统计当前右侧元素与左侧元素组合形成的区间和落在[lower, upper]范围内的个数。
4. 合并完成后,还需要将左右两部分归并排序,以便后续操作可以继续利用已排序的性质加速区间和的计算。
时间复杂度: O(n log n)
空间复杂度: O(n)
class Solution:
def countRangeSum(self, nums, lower, upper):
arr_sum = [0] * len(nums) # 计算前缀和数组
arr_sum[0] = nums[0]
for i in range(1, len(nums)):
arr_sum[i] = arr_sum[i - 1] + nums[i]
return self.process5(arr_sum, 0, len(arr_sum) - 1, lower, upper)
def process5(self, arr, left, right, lower, upper):
if left == right:
return 1 if lower <= arr[left] <= upper else 0
mid = (left + right) // 2
return sum([self.process5(arr, left, mid, lower, upper), self.process5(arr, mid + 1, right, lower, upper),
self.merge5(arr, left, mid, right, lower, upper)])
def merge5(self, arr, left, mid, right, lower, upper):
ans = 0
help_arr = [0] * (right - left + 1) # 辅助数组,用于合并两个子数组
i = 0
p1 = left
p2 = mid + 1
window_l = left
window_r = left
for v in arr[mid + 1: right + 1]:
value_min = v - upper
value_max = v - lower
while window_l <= mid and arr[window_l] < value_min:
window_l += 1
while window_r <= mid and arr[window_r] <= value_max:
window_r += 1
ans += window_r - window_l
while (p1 <= mid) and (p2 <= right):
if arr[p1] <= arr[p2]:
help_arr[i] = arr[p1]
p1 += 1
else:
help_arr[i] = arr[p2]
p2 += 1
i += 1
help_arr[i:] = arr[p1:mid + 1] if p1 <= mid else arr[p2:right + 1] # 处理剩余元素
arr[left: right + 1] = help_arr # 将排序后的数组写回原数组
return ans