问题描述
小U有一个长度为n的整数数组,并且选择了一个有理数 u/v。他现在想知道这个数组中有多少个连续的子区间,其平均值恰好等于 u/v。数组的子区间是指数组中一段连续的元素。
例如,给定数组 [2, 4, 1, 3, 2, 3] 和有理数 5/2,我们需要找出所有平均值等于 5/2 的子区间。
解题思路
-
前缀和数组的计算:
- 初始化一个前缀和数组
prefix_sum,长度为n + 1。 - 遍历数组
arr,计算每个位置的前缀和。
- 初始化一个前缀和数组
-
目标前缀和的计算:
- 对于每个位置
i,计算target = prefix_sum[i] * v - i * u。
- 对于每个位置
-
哈希表的使用:
- 使用哈希表
count_map存储每个target出现的次数。 - 在遍历过程中,检查
target是否已经存在于count_map中,如果存在,则累加结果。 - 更新
count_map中target的值。
- 使用哈希表
算法步骤
- 计算前缀和:
遍历数组arr,计算前缀和数组prefix_sum。 - 遍历前缀和数组:
对于每个i,计算target = prefix_sum[i] \cdot v - i \cdot u。 - 使用哈希表:
使用哈希表count_map存储每个target出现的次数。 - 更新结果:
如果target已经存在于count_map中,说明存在满足条件的子区间,将count_map[target]的值累加到结果中。 - 更新哈希表:
将当前target的值更新到count_map中。
代码实现
def solution(n: int, u: int, v: int, arr: list) -> int:
# 初始化前缀和数组和哈希表
prefix_sum = [0] * (n + 1)
count_map = {}
result = 0
# 计算前缀和
for i in range(1, n + 1):
prefix_sum[i] = prefix_sum[i - 1] + arr[i - 1]
for i in range(n + 1):
# 计算目标前缀和
target = prefix_sum[i] * v - i * u
# 检查哈希表中是否存在目标前缀和
if target in count_map:
result += count_map[target]
# 更新哈希表
if target in count_map:
count_map[target] += 1
else:
count_map[target] = 1
return result
关键步骤解释
- 前缀和计算:
prefix_sum[i]表示arr从0到i-1的和。 - 目标前缀和计算:
target = prefix_sum[i] * v - i * u是为了将平均值条件转换为前缀和的形式。 - 哈希表的使用:
count_map用于存储每个前缀和出现的次数,以便快速查找满足条件的子区间。
时间复杂度
-
前缀和计算:
- 计算前缀和数组
prefix_sum需要遍历整个数组arr一次,时间复杂度为O(n)。
- 计算前缀和数组
-
遍历前缀和数组:
- 遍历前缀和数组
prefix_sum需要遍历n + 1个元素,时间复杂度为O(n)。 - 在每次遍历中,计算
target的时间复杂度为O(1)。 - 检查哈希表
count_map和更新哈希表的时间复杂度为O(1)。
- 遍历前缀和数组
因此,总的时间复杂度为 O(n)。
空间复杂度
-
前缀和数组:
- 前缀和数组
prefix_sum的长度为n + 1,空间复杂度为O(n)。
- 前缀和数组
-
哈希表:
- 哈希表
count_map最多存储n + 1个不同的target值,空间复杂度为O(n)。
- 哈希表
因此,总的空间复杂度为 O(n)。
总结
- 时间复杂度:
O(n) - 空间复杂度:
O(n)