【LC100】No560. 和为 K 的子数组

题目描述

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

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

提示:

  • 1 <= nums.length <= 2 * 104

  • -1000 <= nums[i] <= 1000

  • -107 <= k <= 107

示例

示例 1:

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

示例 2:

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

链接

https://leetcode.cn/problems/subarray-sum-equals-k/description/?envType=study-plan-v2&envId=top-100-liked

思路

一开始想用刚学会的滑动窗口做题,但发现题意不符合单调性,遂作罢。

其实暴力法就能做,枚举出所有子数组,然后判断是否为 k 即可。

但太暴力了,不够优雅。

连续子数组相关问题,我们也可以使用前缀和来考虑。

解法一:前缀和+哈希表

将问题转化为:令 i < j,判断 j 的前缀和减去 i 的前缀和,是否等于 k

先遍历获得前缀和数组。

之后类似于两数之和,我们可以使用哈希表,用 O(1) 的时间获取信息。题目要求返回的是子数组个数,所以哈希表中只需要存放每个前缀和出现的次数即可。

有一个比较特殊的点在:

当 sum[i] == k 时,即前缀和等于 k 的时候,代表此时从 0 到 i 的数组和等于 k,此时 diff 为 0。

如果使用两数之和中 map.containsKey() 的判断,需要先给 map 单独添加 (0, 1) 的键值对。因为 map 中如果不包含 0 的情况,出现上述前缀和等于 k 的情况时,会漏掉计算。

在下方解法中,由于 sum 前缀和数组中有 sum[0] = 0 存在,在第二个循环中,会将 (0, 1) 这种情况在第一步就添加进 map 中。

代码

class Solution {
    public int subarraySum(int[] nums, int k) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        int res = 0;
        int len = nums.length;
        // 设置sum[0] = 0,使sum[i]表示前i个元素的和
        int[] sum = new int[len + 1];
        for (int i = 0; i < len; i++) {
            sum[i + 1] = sum[i] + nums[i];
        }
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < len + 1; i++) {
            int diff = sum[i] - k;
            // 把map中不存在diff就不计算数量,转化为数量+0
            res += map.getOrDefault(diff, 0);
            map.put(sum[i], map.getOrDefault(sum[i], 0) + 1);

        }
        return res;
    }
}
  • 时间复杂度:O(n)

  • 空间复杂度:O(n)


【LC100】No560. 和为 K 的子数组
https://tiamo495.com//archives/lc100-no560.-he-wei-k-de-zi-shu-zu
作者
tiamo495
发布于
2025年07月22日
许可协议