【Leetcode hot 100】560.和为K的子数组

问题链接

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 * 10^4
  • -1000 <= nums[i] <= 1000
  • -10^7 <= k <= 10^7

问题解答

要解决这个问题,我们可以使用前缀和 结合哈希表的方法来高效统计和为 ( k ) 的子数组个数。以下是详细的思路和实现:

思路分析

子数组是数组中连续的非空序列,我们需要统计所有和为 ( k ) 的子数组个数。直接暴力枚举所有子数组的时间复杂度为 ( O(n^2) ),对于较大的数组会超时。因此,我们采用前缀和 + 哈希表的优化方法,将时间复杂度降为 ( O(n) )。

  1. 前缀和定义 :设 prefixSum[i] 表示数组前 i 个元素的和(前缀和)。对于子数组 nums[j..i](从索引 ji,包含两端),其和为 prefixSum[i+1] - prefixSum[j](假设 prefixSum[0] = 0prefixSum[1] = nums[0],以此类推)。
  2. 转化问题 :我们需要找到所有满足 prefixSum[i+1] - prefixSum[j] = kj,即 prefixSum[j] = prefixSum[i+1] - k。因此,遍历数组时,只需统计当前前缀和 currentSum 对应的 currentSum - k 出现的次数即可。
  3. 哈希表优化 :用哈希表 prefixMap 记录前缀和值 及其出现次数 。遍历数组时,实时计算当前前缀和 currentSum,并查询 currentSum - k 在哈希表中的出现次数(即满足条件的 j 的数量),累加到结果中。同时,更新当前前缀和的出现次数到哈希表中。

代码实现

java 复制代码
import java.util.HashMap;
import java.util.Map;

class Solution {
    public int subarraySum(int[] nums, int k) {
        // 哈希表:键为前缀和值,值为该前缀和出现的次数
        Map<Integer, Integer> prefixMap = new HashMap<>();
        // 初始条件:前缀和为 0 的情况出现 1 次(对应子数组从第一个元素开始的情况)
        prefixMap.put(0, 1);
        
        int currentSum = 0; // 当前前缀和
        int result = 0;     // 结果计数
        
        for (int num : nums) {
            currentSum += num; // 计算当前前缀和
            
            // 查询是否存在前缀和为 currentSum - k 的情况,若存在则累加其出现次数
            if (prefixMap.containsKey(currentSum - k)) {
                result += prefixMap.get(currentSum - k);
            }
            
            // 更新当前前缀和的出现次数(若已存在则加 1,否则设为 1)
            prefixMap.put(currentSum, prefixMap.getOrDefault(currentSum, 0) + 1);
        }
        
        return result;
    }
}

代码解释

  1. 哈希表初始化prefixMap.put(0, 1) 是关键初始化步骤。假设数组第一个元素的前缀和为 nums[0],则当 nums[0] == k 时,currentSum - k = 0,此时哈希表中 0 的出现次数为 1,确保该情况被正确统计。
  2. 遍历数组 :逐个元素累加计算当前前缀和 currentSum。对于每个 currentSum,查询 currentSum - k 在哈希表中的出现次数(即有多少个此前的前缀和满足 prefixSum[j] = currentSum - k),并累加到结果。
  3. 更新哈希表 :将当前前缀和 currentSum 的出现次数更新到哈希表中,供后续元素查询使用。

这种方法的时间复杂度为 ( O(n) )(遍历数组一次,哈希表操作均为 ( O(1) )),空间复杂度为 ( O(n) )(哈希表最多存储 ( n ) 个不同的前缀和),高效解决了问题。