560. 和为 K 的子数组

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。

子数组是数组中元素的连续非空序列。

示例 1:

输入:nums = [1,1,1], k = 2
输出:2
示例 2:

输入:nums = [1,2,3], k = 3
输出:2

提示:

1 <= nums.length <= 2 * 104
-1000 <= nums[i] <= 1000
-107 <= k <= 107

这是 一道经典的前缀和 + 哈希表 应用题,考察如何快速找出 和为某个目标值的子数组个数


🧠 解题思路(适用于初学者)

我们要找的是:数组中 和为 k 的连续子数组个数

🔍 暴力解法(不推荐)

  • 枚举所有可能的子数组,计算每个子数组的和,看是否等于 k。
  • 时间复杂度:O(n²)
  • 会超时 ❌

✅ 高效做法:前缀和 + 哈希表(推荐)

核心思想:

如果两个前缀和的差为 k,那么它们之间的子数组和就是 k

假设:

  • 当前前缀和是 pre_sum
  • 我们想找到某个之前的前缀和 pre_sum - k
  • 如果哈希表中有这个 pre_sum - k 出现过,那就说明存在一个子数组的和是 k!

✅ Python 解法

def subarraySum(nums, k):
    from collections import defaultdict
    
    pre_sum_count = defaultdict(int)
    pre_sum_count[0] = 1  # 初始化,表示前缀和为0出现1次

    pre_sum = 0
    count = 0

    for num in nums:
        pre_sum += num
        # 如果 pre_sum - k 存在,说明有一个子数组和为k
        count += pre_sum_count.get(pre_sum - k, 0)
        # 更新哈希表中当前前缀和的次数
        pre_sum_count[pre_sum] += 1

    return count

✅ Java 解法

import java.util.HashMap;

public class Solution {
    public int subarraySum(int[] nums, int k) {
        // key: 前缀和, value: 出现次数
        HashMap<Integer, Integer> preSumCount = new HashMap<>();
        preSumCount.put(0, 1);  // 初始化:前缀和为0出现1次

        int preSum = 0;
        int count = 0;

        for (int num : nums) {
            preSum += num;
            // 检查是否存在 preSum - k
            if (preSumCount.containsKey(preSum - k)) {
                count += preSumCount.get(preSum - k);
            }
            // 更新当前前缀和的出现次数
            preSumCount.put(preSum, preSumCount.getOrDefault(preSum, 0) + 1);
        }

        return count;
    }
}

✅ 示例解释

nums = [1, 1, 1], k = 2 为例:

前缀和序列为:[1, 2, 3]

  • 子数组 [1,1](下标0~1),和为2
  • 子数组 [1,1](下标1~2),和为2

所以输出是 2


📌 小结

技术点解释
前缀和快速计算区间和
哈希表存储前缀和出现次数
时间复杂度O(n)
空间复杂度O(n)

🌟需要理解的三个关键词:

1. 前缀和(prefix sum)

  • 到当前位置为止,所有元素的累加和。

比如:数组 [1, 2, 3] 的前缀和依次是:

  • 第0个元素:1
  • 第1个元素:1 + 2 = 3
  • 第2个元素:1 + 2 + 3 = 6

2. 目标:找出所有和为 k 的连续子数组

我们希望找到某个区间 i ~ j,它的和等于 k
设:

pre_sum[j] = 前 j 项的和
pre_sum[i-1] = 前 i-1 项的和

那么:

pre_sum[j] - pre_sum[i-1] = k

也就是:

pre_sum[i-1] = pre_sum[j] - k

如果我们记录了所有的 前缀和,就可以通过查找 pre_sum - k 是否存在,来判断是否有某段子数组的和为 k。


3. 哈希表记录前缀和的出现次数

pre_sum_count[前缀和] = 出现的次数

✅ 现在来看你问的这句代码:

count += pre_sum_count.get(pre_sum - k, 0)

意思是:

当前累加的前缀和是 pre_sum
我们想找有没有 之前出现过 的某个 pre_sum - k

  • 如果有,那说明从那个位置之后到当前位置这段区间的和是 k
  • 它出现几次,就代表有几个子数组满足要求

🔍 举个完整例子:

nums = [1, 2, 1, 1], k = 3

依次计算前缀和,并用字典记录每个前缀和出现的次数:

步骤numpre_sumpre_sum - kpre_sum_count[pre_sum - k]count
011-200
12301 ←初始 pre_sum=01
214112
315202

最终答案是 2


🧾总结:

count += pre_sum_count.get(pre_sum - k, 0)

👉 就是问:

有没有出现过 pre_sum - k 这个前缀和?出现了几次?

  • 有几次,就有几个子数组以当前结尾,和为 k
  • 所以要加上这个次数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值