LeetCode 热题 HOT 100(子串)560. 和为K的子数组

108 阅读3分钟

题目简介

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 的连续子数组的个数,我们可以使用前缀和+哈希表的方法来解决,这是一种高效的 O(n) 解法。

思路分析

  1. 前缀和的概念:前缀和是指从数组起始位置到当前位置的所有元素之和
  • 如果我们有前缀和 prefixSum[i] 表示 nums[0...i] 的和
  • 那么任意子数组 nums[i...j] 的和可以表示为 prefixSum[j] - prefixSum[i-1]
  1. 利用哈希表优化
  • 我们需要找到满足 prefixSum[j] - prefixSum[i-1] = k 的所有 (i, j) 对
  • 问题转化为求 prefixSum[i-1] = prefixSum[j] - k 的所有(i, j)对
  • 在遍历过程中,我们检查当前前缀和减去 k 的值是否在哈希表中出现过(i < j)
  • 将当前前缀和加入到哈希表中
  1. 具体算法流程
  • 初始化哈希表,记录前缀和出现的次数,初始{0: 1}(表示空前缀出现 1 次,这是算法继续执行的前提驱动条件)
  • 遍历数组,累加前缀和
  • 检查 prefixSum - k 是否在哈希表中,若存在更新相应计数
  • 将当前前缀和加入到哈希表

代码实现

func subarraySum(nums []int, k int) int {
    count := 0
    sum := 0
    preSum := make(map[int]int)
    preSum[0] = 1
    
    for _, num := range nums {
        sum += num  // 计算当前前缀和
        if val, exists := preSum[sum-k]; exists {
            count += val  // 如果存在 sum-k 的前缀和,说明有 val 个子数组的和为 k
        }
        preSum[sum]++     // 更新前缀和的出现次数
    }
    return count
}

复杂度分析

  • 时间复杂度:O(n),其中 n 是数组长度,只需要遍历一次数组
  • 空间复杂度:O(n),最坏情况下哈希表需要存储 n 个不同的前缀和
  1. 前缀和的作用:通过前缀和,我们可以在O(1)时间内计算任意子数组的和
  2. 哈希表的作用:记录每个前缀和出现的次数,帮助我们快速找到满足条件的子数组
  3. 初始化preSum[0]=1的意义:表示空前缀和出现一次,处理从数组起始位置开始的子数组

这种方法巧妙地将O(n²)的暴力解法优化到了O(n),是一种典型的空间换时间的策略。

算法流程图

image.png

举例说明

让我们最后通过一个具体例子来解释算法的执行过程:

对于示例1: nums = [1,1,1], k = 2

步骤当前元素前缀和(sum)查找preSum[sum-k]计数(count)前缀和映射(preSum)
初始-0-0{0:1}
111preSum[1-2]不存在0{0:1, 1:1}
212preSum[2-2]=preSum[0]=11{0:1, 1:1, 2:1}
313preSum[3-2]=preSum[1]=12{0:1, 1:1, 2:1, 3:1}

最终结果为2,表示有2个和为k的子数组:[1,1]和[1]。