青训营X豆包MarsCode - 第二篇滑窗- 370| 豆包MarsCode AI 刷题
氦嗨氦,让我们继续滑!上期写了个中等的sharing,这次挑了个Hard,让
“各位提瓦特大陆的探索者,今天我们将扮演不同角色,一起来解决一个关于数组子区间平均值的有趣问题,逐步揭开MarsCode刷题的真相!”
不说俏皮话了,题号 370-Hard-子区间平均值问题。
题目原文
小U有一个长度为n的整数数组,并且选择了一个有理数
u/v。他现在想知道这个数组中有多少个连续的子区间,其平均值恰好等于u/v。数组的子区间是指数组中一段连续的元素。例如,给定数组
[2, 4, 1, 3, 2, 3]和有理数5/2,我们需要找出所有平均值等于5/2的子区间。
题目抽象分析
“我们要找出数组中所有连续子区间的平均值等于给定的有理数 u/v 的个数”:
-
连续子区间
- 还要是所有
-
约束条件 = 平均值blabla
题目类型
这个问题属于数组与滑动窗口类型,因为我们需要在数组中滑动一个窗口来计算不同子区间的平均值。
整体思路
既然是所有符合条件的子区间,那mo,为了实现这一点,我们可以采用滑动窗口的方法,遍历数组中的每一个可能的子区间,并计算其平均值。
- 如果平均值等于
u/v,计数器加一,然后return即可。
代码分块解析
-
初始化计数器:
count用于记录符合条件的子区间数量。 -
遍历数组:双层循环needed
- 使用外层循环来确定子区间的起始位置。
- 滑动窗口:使用内层循环来扩展窗口,计算当前窗口的平均值。
-
计算平均值:
window_avg用于存储当前窗口的平均值。- 条件约束判断并++ :如果
window_avg等于u/v,则将count加一。
-
窗口移动:
- 移除窗口最开始的元素,并移动窗口的起始位置。
解题步骤
- 初始化计数器
count为 0。 - 使用外层循环遍历数组的每一个元素,作为子区间的起始位置。
- 对于每个起始位置,使用内层循环扩展窗口,计算当前窗口的平均值。
- 如果当前窗口的平均值等于
u/v,则将count加一。 - 移除窗口最开始的元素,并移动窗口的起始位置。
- 重复步骤3-5,直到窗口扩展到数组末尾。
- 返回
count作为最终结果。
代码
def solution(n: int, u: int, v: int, arr: list) -> int:
# 初始化计数器
count = 0
# 遍历数组,每次遍历计算窗口的平均值
for i in range(n):
# 窗口的起始位置
start = i
# 窗口的结束位置
end = i
# 窗口内元素的总和
total = 0
# 计算窗口内元素的总和
while end < n:
total += arr[end]
end += 1
# 计算窗口的平均值
window_avg = total / (end - start)
# 如果窗口的平均值等于 u/v,则计数器加1
if window_avg == u / v:
count += 1
# 窗口移除最开始的元素
total -= arr[start]
start += 1
return count
# 测试
if __name__ == '__main__':
print(solution(6, 5, 2, [2, 4, 1, 3, 2, 3]) == 6)
print(solution(5, 1, 1, [1, 1, 1, 1, 1]) == 15)
print(solution(4, 2, 1, [2, 2, 2, 2]) == 10)
复杂度分析
参考了别的老哥的写法环节,我也来试试复杂度分析
- 时间复杂度:,、我们有两层循环来确定子区间的起始和结束位置,虽然可能应该或许没有到,但是最坏就是(?)
- 空间复杂度: ,和n没啥关系。
总结
虽然是Hard,但依旧是直观且易于理解的Solution。
打油诗已无灵感,环节pass,继续前进,朋友们,让我们一起在代码的世界中遨游!