930 和相同的二元子数组-中等

题目:

给你一个二元数组 nums ,和一个整数 goal ,请你统计并返回有多少个和为 goal非空 子数组。

子数组 是数组的一段连续部分。

分析:

整体思路是求数组的前缀和,假设有两个坐标 i 和 j,且 i < j。

前 i 个元素的和为 sum_i,前 j 个元素的和为 sum_j,如果 sum_j - sum_i = goal;

那么区间[i, j] 就是一种解。

考虑到数组中只有 0 和 1,那么当元素为 0 的时候,前缀和的大小不变,但前缀和的个数增加了。这个个数是要计算到总结果中的,因为不包含该元素 0 和包含该元素 0 都是非空子数组。

假设,sum_i 等于 3 出现了4次,sum_j 等于 5 出现了 3 次,在 goal 为 2 的情况下。

sum_j 等于 5 连续出现 3 次,对最终的结果增加了 4+4+4, 总共 12 次。【这是11-13行代码】

// date 2023/11/21
func numSubarraysWithSum(nums []int, goal int) int {
    var ans int
  	// 因为后面判断使用的时候是 sum-goal, 所以 sum 初始化为 0
	  sum := 0
    cnt := make(map[int]int, 16)  // 记录 前缀和 出现的次数

    for _, v := range nums {
        cnt[sum]++ // 前缀和 次数递增
        sum += v   // 前缀求和
				// 每次都要计算
      	// 如果存在,表示 当前元素 和 之前的前缀和 能够构成一个解,
      	// 之前的前缀和 出现过几次,就是几个不同的非空子数组
        if ct, ok := cnt[sum-goal]; ok {
            ans += ct
        }
    }

    return ans
}

最后更新于