📜  总和等于其长度的子数组的计数 | 2套(1)

📅  最后修改于: 2023-12-03 15:39:36.314000             🧑  作者: Mango

总和等于其长度的子数组的计数

介绍

给定一个由非负整数构成的数组 nums,你的任务是计算存在多少个连续子数组,它们的总和等于其长度。

示例

输入: nums = [1,2,3,4,5] 输出: 0 解释: 不存在这样的子数组

输入: nums = [2,3,1,7,4] 输出: 2 解释: 子数组 [2,3], [4,5] 的总和与长度相等

解法
双指针

使用两个指针 ij 向右遍历数组 nums,其中 i 为子数组的起始位置,j 为子数组的结束位置。用 sum 记录以 j 结尾的子数组的和。当 sum == j - i + 1 时,说明找到了一个符合条件的子数组,计数器 ans 加一。

def countSubArray(nums: List[int]) -> int:
    ans = 0
    sum = 0
    i = 0
    for j in range(len(nums)):
        sum += nums[j]
        while i < j and sum > j - i + 1:
            sum -= nums[i]
            i += 1
        if sum == j - i + 1:
            ans += 1
    return ans

复杂度分析:

  • 时间复杂度:$O(n)$
  • 空间复杂度:$O(1)$
前缀和

使用一个哈希表 prefixSum 记录以当前位置 j 结尾的所有子数组的和为键,出现次数为值。即 prefixSum[sum] 表示数组 nums 中有多少个子数组的和为 sum,且该子数组的结束位置为 j。当遍历到某个位置 j 时,假设前面出现过和为 sum 的子数组,其起始位置为 i,则说明从 i+1j 的所有子数组的和都等于其长度。因此当前位置的答案即为 prefixSum[sum]

def countSubArray(nums: List[int]) -> int:
    ans = 0
    prefixSum = {0: 1}
    sum = 0
    for j in range(len(nums)):
        sum += nums[j]
        if sum - j - 1 in prefixSum:
            ans += prefixSum[sum - j - 1]
        prefixSum[sum - j - 1] = prefixSum.get(sum - j - 1, 0) + 1
    return ans

复杂度分析:

  • 时间复杂度:$O(n)$
  • 空间复杂度:$O(n)$
总结

本题可以使用双指针或前缀和两种方法来解决。双指针法可以更好地节约内存空间,但会产生一些不必要的计算;前缀和法虽然需要较多的空间,但很容易统计答案。在实际应用中,可以根据具体情况来选择合适的算法。