☰
力扣560题:前缀和与哈希表优化子数组求和
2026/10/26 18:43:01 网站建设 项目流程

1. 题目背景与核心挑战

这道来自力扣hot100的经典题目"和为 K 的子数组"(LeetCode 560. Subarray Sum Equals K)看似简单,实则暗藏玄机。作为数组类问题的典型代表,它考察的不仅是基础编程能力,更是对算法优化思维的深度理解。

题目要求很简单:给定一个整数数组nums和一个整数k,统计该数组中和为k的连续子数组的个数。比如nums = [1,1,1],k=2时,返回2(因为前两位和后两位的和都是2)。但当你真正开始coding时,会发现暴力解法在数据量稍大时就会超时。

关键提示:这道题O(n²)的暴力解法虽然直观,但在力扣上会直接超时。必须找到O(n)或O(nlogn)的优化方案才能通过所有测试用例。

2. 暴力解法与优化思路

2.1 直观的暴力枚举法

最直接的思路是双重循环枚举所有可能的子数组:

def subarraySum(nums, k): count = 0 n = len(nums) for i in range(n): sum = 0 for j in range(i, n): sum += nums[j] if sum == k: count += 1 return count

这种方法时间复杂度O(n²),空间复杂度O(1)。当n=10⁵时,计算量将达到10¹⁰次操作,远超力扣的时间限制。

2.2 前缀和优化思路

聪明的解法是利用前缀和(Prefix Sum)技巧。前缀和的定义是:prefix[i]表示nums[0]到nums[i-1]的和。这样任意子数组nums[i..j]的和可以表示为prefix[j+1] - prefix[i]。

基于这个性质,我们可以将问题转化为:找到所有满足prefix[j+1] - prefix[i] == k的(i,j)对。这等价于寻找prefix[i] == prefix[j+1] - k。

3. 哈希表优化实现

3.1 算法核心思想

使用哈希表存储前缀和的出现次数,可以在O(1)时间内查询所需的前缀和值。具体步骤:

  1. 初始化哈希表prefix_sum = {0:1}(和为0出现1次)
  2. 维护当前前缀和current_sum
  3. 遍历数组时,计算current_sum += nums[i]
  4. 检查current_sum - k是否在哈希表中,如果在则count += prefix_sum[current_sum - k]
  5. 更新current_sum的出现次数

3.2 完整实现代码

def subarraySum(nums, k): count = 0 prefix_sum = {0: 1} current_sum = 0 for num in nums: current_sum += num if (current_sum - k) in prefix_sum: count += prefix_sum[current_sum - k] prefix_sum[current_sum] = prefix_sum.get(current_sum, 0) + 1 return count

3.3 复杂度分析

  • 时间复杂度:O(n),只需一次遍历
  • 空间复杂度:O(n),最坏情况下需要存储n个不同的前缀和

4. 边界条件与特殊测试用例

4.1 必须考虑的边界情况

  1. 空数组:nums = [], k=0 → 返回0
  2. 单个元素等于k:nums = [1], k=1 → 返回1
  3. 多个相同元素:nums = [1,1,1], k=2 → 返回2
  4. 包含负数:nums = [-1,-1,1], k=0 → 返回1
  5. k=0的特殊情况:nums = [0,0,0], k=0 → 返回6

4.2 测试用例验证表

测试用例预期输出说明
[1], 11单个元素
[1,2,3], 32正常情况
[1,-1,0], 03包含0和负数
[0,0,0], 06全0数组
[1], 00k=0无解

5. 算法优化技巧与心得

5.1 关键优化点

  1. 哈希表初始化必须包含{0:1},否则会漏算从数组开头开始的子数组
  2. 更新哈希表应该在检查之后,避免重复计数
  3. 使用get方法可以简化代码,避免KeyError异常

5.2 常见错误排查

  1. 错误:忘记初始化{0:1}

    • 现象:漏算从第一个元素开始的子数组
    • 示例:nums = [1], k=1会返回0而不是1
  2. 错误:先更新哈希表再检查

    • 现象:会错误计算空子数组
    • 示例:nums = [1], k=0会返回1而不是0
  3. 错误:使用数组存储前缀和

    • 现象:查找效率低导致超时
    • 解决方案:必须使用哈希表实现O(1)查找

5.3 性能优化实测

在力扣平台上实测结果:

  • 暴力解法:在n=20000时超时(>2000ms)
  • 前缀和+哈希表:相同规模仅需40ms左右

6. 同类问题扩展

掌握了这个技巧后,可以解决一系列类似问题:

  1. 最长的和为k的子数组(LeetCode 325)
  2. 和为k的子矩阵(LeetCode 1074)
  3. 乘积为k的子数组(LeetCode 713)
  4. 0和1数量相等的子数组(LeetCode 525)

这类问题的共同特点是:

  • 都需要统计满足某种条件的连续子数组/子矩阵
  • 都可以通过前缀和/积+哈希表的组合来优化
  • 都需要特别注意边界条件和初始化值

7. 刷题策略建议

对于力扣hot100这类高频题库:

  1. 先理解暴力解法,确保完全掌握问题本质
  2. 分析暴力解法的时间瓶颈在哪里
  3. 寻找可以将O(n²)降为O(n)或O(nlogn)的数学性质或数据结构
  4. 特别注意边界条件和特殊测试用例
  5. 记录每种题型的解题模板,形成肌肉记忆

这道"和为k的子数组"作为hot100的经典题目,几乎包含了数组类问题的所有考察要点。掌握它的优化思路后,你会发现很多其他题目都是这个模式的变种。这也是为什么它会被选入hot100题库 - 它不仅考察编码能力,更考察你能否从暴力解法中发现优化规律的能力。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询