【力扣-560. 和为 K 的子数组🚀】Python笔记

1 阅读4分钟

一、前置知识点:前缀和 + 哈希表

1. 前缀和(Prefix Sum)

  • 定义prefix_sum[i] 表示数组从第 0 个元素到第 i 个元素的累加和。
  • 核心公式:子数组 [j+1, i] 的和 = prefix_sum[i] - prefix_sum[j]
  • 作用:将 “计算区间和” 的操作从 O (n) 优化到 O (1),是解决子数组和问题的基础。

2. 哈希表统计频次

  • 作用:快速记录并查询某个前缀和出现的次数,避免重复遍历。
  • 关键思想:若 prefix_sum[i] - prefix_sum[j] = k,则 prefix_sum[j] = prefix_sum[i] - k。遍历数组时,用哈希表保存已出现过的 prefix_sum 及其次数,即可在 O (1) 时间内找到满足条件的 j 的数量。

3. 初始化技巧

  • 哈希表初始化为 {0: 1},表示 “前缀和为 0 时出现了 1 次”,用于处理从数组开头到当前位置的子数组和恰好为 k 的情况。

二、经典算法题:和为 K 的子数组(LeetCode 560)

题目描述

给定一个整数数组 nums 和一个整数 k,请你统计并返回该数组中和为 k 的子数组的个数。子数组是数组中元素的连续非空序列。

示例

  • 输入nums = [1, 1, 1, 1]k = 2
  • 输出3
  • 解释:和为 2 的子数组有 [1,1](索引 0-1)、[1,1](索引 1-2)、[1,1](索引 2-3),共 3 个。

最优解法:前缀和 + 哈希表

核心思路

  1. 遍历数组,维护当前前缀和 prefix_sum
  2. 查询哈希表:若 prefix_sum - k 存在于哈希表中,则说明之前有 prefix_count[prefix_sum - k] 个子数组的和为 k,将其累加到结果中。
  3. 更新哈希表:将当前前缀和 prefix_sum 加入哈希表,记录其出现次数。
  4. 时间复杂度:O (n),仅遍历一次数组;空间复杂度:O (n),用于存储哈希表。

代码实现

from typing import List 
class Solution: 
    def subarraySum(self, nums: List[int], k: int) -> int: 
        prefix_count = {0: 1} # 初始化:前缀和0出现1次 
        pre_sum = 0 
        result_count = 0 
        
        for num in nums:
            pre_sum += num # 更新当前前缀和 
            target = pre_sum - k # 要找的历史前缀和 
            
            # 如果target存在,说明有对应子数组,累加次数 
            if target in prefix_count: 
                result_count += prefix_count[target]
                
            # 更新当前前缀和的出现次数 
            prefix_count[pre_sum] = prefix_count.get(pre_sum, 0) + 1 
            
        return result_count

代码执行示例

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

  1. 初始化:prefix_count = {0:1}pre_sum=0result_count=0
  2. num=1pre_sum=1target=1-2=-1(不存在)→ prefix_count={0:1, 1:1}
  3. num=1pre_sum=2target=2-2=0(存在,次数 1)→ result_count=1prefix_count={0:1, 1:1, 2:1}
  4. num=1pre_sum=3target=3-2=1(存在,次数 1)→ result_count=2prefix_count={0:1, 1:1, 2:1, 3:1}
  5. num=1pre_sum=4target=4-2=2(存在,次数 1)→ result_count=3prefix_count={0:1, 1:1, 2:1, 3:1, 4:1}
  6. 最终返回 3,与示例结果一致。

三、关键知识点总结

1. 暴力解法对比

  • 暴力法:遍历所有子数组,计算和并判断是否为 k,时间复杂度 O (n²),在数据量大时会超时。
  • 前缀和 + 哈希表:将时间复杂度优化到 O (n),是解决此类问题的标准高效解法。

2. 去重与计数逻辑

  • 无需去重:题目允许多个相同的子数组,哈希表直接记录每个前缀和出现的次数即可。
  • 核心计数result_count += prefix_count[target],表示有多少个历史前缀和能与当前前缀和组成和为 k 的子数组。

3. 适用场景拓展

前缀和 + 哈希表的组合,适用于以下类型题目:

  • 和为目标值的子数组:如本题、LeetCode 523(连续的子数组和)
  • 区间和问题:如统计和为 0 的子数组、和为奇数 / 偶数的子数组
  • 连续子数组最值:如最长和为 k 的子数组

四、算法优化点回顾

优化点作用
前缀和将区间和计算从 O (n) 降为 O (1)
哈希表快速查询历史前缀和,避免二次遍历
初始化 {0:1}处理从数组开头到当前位置的子数组和为 k 的情况
一次遍历整体时间复杂度降为 O (n),空间复杂度 O (n)