560.和为K的子数组
我的题解:暴力,因为我实在想不到其他解法了┭┮﹏┭┮还超时了这里就不放出来了。太菜了
官方题解:前缀和+哈希表
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
s = [0] * (len(nums) + 1)
for i, x in enumerate(nums):
s[i + 1] = s[i] + x
cnt = defaultdict(int)
ans = 0
for sj in s:
ans += cnt[sj - k]
cnt[sj] += 1
return ans
这段代码是解决「和为 K 的子数组」(LeetCode 560)问题的经典解法,使用了前缀和(Prefix Sum) + 哈希表优化的思想。下面按照你要求的格式,先解释关键函数和表达式的含义,再逐段解析整体逻辑。
🔹 关键函数与表达式说明
1. s = [0] * (len(nums) + 1)
- 创建一个长度为
n + 1的前缀和数组s,其中s[0] = 0。 - 定义:
s[i] = nums[0] + nums[1] + ... + nums[i-1],即前i个元素的和。 - 这样设计的好处是:任意子数组
nums[i:j](左闭右开)的和可表示为s[j] - s[i]。
2. defaultdict(int)
- 来自
collections模块,是一个默认值为0的字典。 - 当访问一个不存在的键时,不会报错,而是自动创建该键并赋值为
0。 - 用于高效统计某个前缀和出现的次数。
3. ans += cnt[sj - k]
- 核心思想:我们想找有多少对
(i, j)满足s[j] - s[i] = k,即s[i] = s[j] - k。 - 对于当前前缀和
sj = s[j],只要知道之前有多少个前缀和等于sj - k,就能得到以j结尾、和为k的子数组个数。 cnt[sj - k]正是这个数量。
4. cnt[sj] += 1
- 将当前前缀和
sj记录到哈希表中,供后续位置使用。 - 注意:先查询
sj - k,再更新cnt[sj],避免把当前前缀和自己也算进去(因为子数组长度至少为 1,i < j)。
🔸 整体逻辑解析
步骤 1:构建前缀和数组
s = [0] * (len(nums) + 1)
for i, x in enumerate(nums):
s[i + 1] = s[i] + x
例如:nums = [1, 2, 3] → s = [0, 1, 3, 6]
s[0] = 0s[1] = 1s[2] = 1+2 = 3s[3] = 1+2+3 = 6
子数组 nums[1:3] = [2,3] 的和 = s[3] - s[1] = 6 - 1 = 5
步骤 2:遍历前缀和,用哈希表统计满足条件的对数
cnt = defaultdict(int)
ans = 0
for sj in s:
ans += cnt[sj - k]
cnt[sj] += 1
- 初始化
cnt为空,但隐含cnt[0] = 0(尚未记录)。 - 关键点:在循环开始时,
cnt中只包含当前sj之前的前缀和。
🌰 举例说明
设 nums = [1, 1, 1], k = 2
前缀和 s = [0, 1, 2, 3]
遍历过程:
sj | sj - k | cnt[sj - k] | ans 累加后 | 然后执行 cnt[sj] += 1 |
|---|---|---|---|---|
| 0 | -2 | 0 | 0 | cnt[0] = 1 |
| 1 | -1 | 0 | 0 | cnt[1] = 1 |
| 2 | 0 | 1 | 1 | cnt[2] = 1 |
| 3 | 1 | 1 | 2 | cnt[3] = 1 |
最终 ans = 2,对应子数组 [1,1](索引 01)和 [1,1](索引 12),正确。
💡 为什么一开始
cnt[0]要被计入?
因为当sj == k时,sj - k = 0,而s[0] = 0表示“从开头到当前位置”的子数组。所以必须让cnt[0]在适当时候为 1 —— 这正是通过先查询、后更新,并且从s[0]=0开始遍历实现的。
📊 复杂度分析
-
时间复杂度:O(n)
只需一次遍历计算前缀和,再一次遍历统计答案,每次哈希操作 O(1)。 -
空间复杂度:O(n)
前缀和数组s占 O(n),哈希表cnt最多存 n+1 个不同前缀和。
⚡ 优化提示:其实可以不用显式存储整个
s数组,边遍历nums边维护当前前缀和,将空间优化到 O(1)(除哈希表外)。但当前写法逻辑更清晰。
总结
这段代码的核心思想是:
子数组和 = 两个前缀和之差。
要找sum(i, j) = k,等价于找s[j] - s[i] = k,即s[i] = s[j] - k。
用哈希表记录所有已出现的s[i]的频次,就能在 O(1) 时间内知道有多少个i满足条件。
通过前缀和 + 哈希表计数,将暴力 O(n²) 的解法优化到 O(n),是处理“子数组和”类问题的标准范式。
100题:560.和为K的子数组&spm=1001.2101.3001.5002&articleId=154641467&d=1&t=3&u=f708a0c7dc004ab5b2aad761386ea5af)
1022

被折叠的 条评论
为什么被折叠?



