在问 · 算法题解

560. 和为 K 的子数组

中等哈希表前缀和 + 哈希表力扣原题 ↗

题目描述

输入整数数组 nums 和整数 k。

子数组指数组中一段连续且非空的元素。统计所有元素之和恰好等于 k 的子数组有多少个,并返回这个数量。

起止位置不同的子数组分别计数,即使它们的元素内容一样。数组中可能有负数和 0。

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

解释:下标 [0,1] 和 [1,2] 两段的和都是 2。

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

解释:[1,2] 和 [3] 两段的和都是 3。

数据范围

  • 1 <= nums.length <= 2 * 10^4
  • -1000 <= nums[i] <= 1000
  • -10^7 <= k <= 10^7

解题思路:前缀和 + 哈希表

令 prefix 为当前位置前缀和。若此前出现过 prefix-k,说明对应前缀到当前位置的和为 k;用频次表累计。

为什么正确

处理当前位置前,freq[x] 是前面所有前缀和 x 的出现次数。

复杂度分析

时间 O(n),空间 O(n)。

易错点

只保存前缀和是否出现会漏算重复前缀,必须保存频次。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def subarraySum(self, nums,k):
        freq={0:1}; prefix=ans=0
        for x in nums:
            prefix += x
            ans += freq.get(prefix-k,0)
            freq[prefix]=freq.get(prefix,0)+1
        return ans

载入编辑器,自己跑一遍 →

其他解法

枚举法对每个终点重新遍历所有起点;前缀和 + 哈希表把“存在多少个起点”变成一次查表,用 O(n) 空间换到 O(n) 时间。

解法 2:枚举子数组起点 时间 O(n²),空间 O(1)

枚举子数组的起点 i。从 i 向右扩展终点 j,边扩展边累加元素和。每次和等于 k 就计数加一。

不占额外空间,思路最直接。n 达到 2×10⁴ 时要约 2×10⁸ 次加法,比前缀和慢很多。数组有负数,所以不能用滑动窗口剪枝。

class Solution:
    def subarraySum(self, nums, k):
        n = len(nums)
        ans = 0
        for i in range(n):
            s = 0
            for j in range(i, n):
                s += nums[j]
                if s == k:
                    ans += 1
        return ans

哈希表 专题的其他题目

查看 哈希表 全部题目 →