560. 和为K的子数组(Python)

本文探讨了寻找数组中和为特定值k的连续子数组个数的三种算法:暴力法、前缀和法及前缀和结合字典的高效解决方案。通过实例解释了每种方法的工作原理,并详细阐述了前缀和加字典法的思路,包括如何利用前缀和快速计算子数组和以及如何避免重复计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。

示例 1 :

输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。

方法一:暴力法,会超时。

class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
        cnt, n =  0, len(nums)
        for i in range(n):
            for j in range(i, n):
                if (sum(nums[i:j + 1]) == k): cnt += 1
        return cnt

方法二:前缀和,会超时。

class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
      cnt, n =  0, len(nums)
      pre = [0] * (n + 1)
      for i in range(1, n + 1):
          pre[i] = pre[i - 1] + nums[i - 1]
      for i in range(1, n + 1):
          for j in range(i, n + 1):
              if (pre[j] - pre[i - 1] == k): cnt += 1
      return cnt

方法三:前缀和+字典
第一点:

使用前缀数组的一大好处是可用 pre(b) - pre(a-1) 来表示 a->b 中这段中数组的和。这个 a-1 可以不用那么纠结。重点理解思想。

比如 前5项的和 - 前3项的和 = 第4项~第5项的和。 (1+2+3+4+5) - (1+2+3) = 4+5

或者说 pre(b) - pre(a) 等同于 a+1~b 的和。这样子更好理解一些。

第二点:

因为这个列表是有负数的。因此前缀和不是单调递增的。相应的前缀和之差也是。比如有个点的前缀和是10,我们目标值是3,那么倒回去找一个前缀和为7的点。可能会有两个。如图所示。

class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
        # num_times 存储某“前缀和”出现的次数,这里用collections.defaultdict来定义它
        # 如果某前缀不在此字典中,那么它对应的次数为0
        num_times = collections.defaultdict(int)
        num_times[0] = 1  # 先给定一个初始值,代表前缀和为0的出现了一次
        cur_sum = 0  # 记录到当前位置的前缀和
        res = 0
        for i in range(len(nums)):
            cur_sum += nums[i]  # 计算当前前缀和
            if cur_sum - k in num_times:  # 如果前缀和减去目标值k所得到的值在字典中出现,即当前位置前缀和减去之前某一位的前缀和等于目标值
                res += num_times[cur_sum - k]
            # 下面一句实际上对应两种情况,一种是某cur_sum之前出现过(直接在原来出现的次数上+1即可),
            # 另一种是某cur_sum没出现过(理论上应该设为1,但是因为此处用defaultdict存储,如果cur_sum这个key不存在将返回默认的int,也就是0)
            # 返回0加上1和直接将其置为1是一样的效果。所以这里统一用一句话包含上述两种情况
            num_times[cur_sum] += 1
        return res

参考链接:https://leetcode-cn.com/problems/subarray-sum-equals-k/solution/xiong-mao-shua-ti-python3-qian-zhui-he-zi-dian-yi-/
参考链接:https://leetcode-cn.com/problems/subarray-sum-equals-k/solution/python3-qian-zhui-he-hashmap-by-mu-ren-6/

### LeetCode 'Subarray Sum Equals K' 的 Python 解法 以下是针对该问题的一个高效解决方案,时间复杂度为 \(O(n)\),空间复杂度为 \(O(n)\)[^3]。 此方法的核心思想是利用前缀以及哈希表来记录之前计算过的累积及其出现次数。通过这种方式可以快速判断当前累积减去目标值 \(k\) 是否已经存在于之前的累积中。 #### 实现代码 ```python class Solution: def subarraySum(self, nums, k): """ :type nums: List[int] :type k: int :rtype: int """ count = {0: 1} # 初始化哈希表,表示累积为0的情况出现了1次 cur_sum = 0 # 当前累积初始化为0 result = 0 # 符合条件的子数组数量 for num in nums: cur_sum += num # 更新当前累积 # 如果 (cur_sum - k) 存在于哈希表中,则找到符合条件的子数组 if (cur_sum - k) in count: result += count[cur_sum - k] # 将当前累积加入到哈希表中,更新其出现次数 if cur_sum in count: count[cur_sum] += 1 else: count[cur_sum] = 1 return result # 返回最终的结果 ``` 上述实现的关键点如下: - 使用 `count` 字典存储累积及其对应的出现次数。 - 遍历过程中不断累加当前元素至 `cur_sum` 中,并检查 `(cur_sum - k)` 是否已存在于字典中。如果存在,则表明找到了若干个满足条件的连续子数组[^4]。 - 时间复杂度主要由单层循环决定,因此整体效率较高。 ### 示例运行 对于输入 `nums = [1, 1, 1]`, `k = 2`: 执行过程如下: - 初始状态:`cur_sum=0`, `result=0`, `count={0: 1}` - 处理第一个数 `num=1`: - 更新 `cur_sum=1` - 检查 `cur_sum-k=-1` 不在 `count` 中 - 更新 `count={0: 1, 1: 1}` - 处理第二个数 `num=1`: - 更新 `cur_sum=2` - 检查 `cur_sum-k=0` 在 `count` 中,增加 `result+=1` - 更新 `count={0: 1, 1: 1, 2: 1}` - 处理第三个数 `num=1`: - 更新 `cur_sum=3` - 检查 `cur_sum-k=1` 在 `count` 中,增加 `result+=1` - 更新 `count={0: 1, 1: 1, 2: 1, 3: 1}` 最终返回结果为 `result=2`[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI小笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值