Given a binary array nums and an integer goal, return the number of non-empty subarrays with a sum goal.

subarray is a contiguous part of the array.

solutions

hashmap of prefix sum frequencies

Very similar to other problems like 523-continuous-subarray-sum and 560-subarray-sum-equals-k.

We can use a hashmap to store frequencies of our prefix sums, and lookback as we traverse to accumulate our total answer of subarrays.

// O(n), O(n) space
class Solution {  
	public int numSubarraysWithSum(int[] nums, int goal) {  
		HashMap<Integer, Integer> prefixes = new HashMap<>();  
		prefixes.put(0, 1);  
		
		int res = 0;  
		int prefix = 0;  
		
		for (int val : nums) {  
			prefix += val;  
		
			if (prefixes.containsKey(prefix-goal)) {  
				res += prefixes.get(prefix-goal);  
			}  
			prefixes.put(prefix, prefixes.getOrDefault(prefix, 0)+1);  
		}  
		
		return res;  
	}  
}

two pointers

We normally could two pointer this pretty easily, but it’s more tricky as zeroes mean that we could expand/contract our window while keeping the same window sum.

The key realization is that if we have some subarray [0,0,1,1], the number of subarrays that sum to 2 is equal to one plus the number of prefix zeroes. In this case, we have [0,0,1,1], [0,1,1], and [1,1].

So, we can use a modified sliding window approach, where we move our left window pointer up while window_sum > goal (the normal condition), as well as when nums[l] == 0. While we do this, we can keep track of how many unbroken prefix zeroes exist before our window. If we see a 1, we reset this number.

Then, after we’ve shrunk our window, if window_sum == goal, we use the prior logic and add 1+prefix_zeros to our answer.

class Solution:  
	def numSubarraysWithSum(self, nums: List[int], goal: int) -> int:  
	l = 0  
	window_sum = 0  
	prefix_zeros = 0  
	res = 0  
	
	# [1,0,0,1,1]  
	# [1,0,0,1] -> prefix_zeroes = 0, res += 1  
	# [1,0,0,1,1] -> now shrink  
	# shrink: [0,0,1,1] -> prefix_zeroes = 0  
	# shrink: [0,1,1] -> prefix_zeroes = 1  
	# shrink: [1,1] -> prefix_zeroes = 2 (done shrinking)  
	# res += 1 + 2  
	for r in range(len(nums)):  
		window_sum += nums[r]  
	
		while l < r and (nums[l] == 0 or window_sum > goal):  
			if nums[l] == 1:  
				prefix_zeros = 0  
			else:  
				prefix_zeros += 1  
	
			window_sum -= nums[l]  
			l += 1  
	
		if window_sum == goal:  
			res += 1 + prefix_zeros  
	
	return res