Browse curriculum

Binary Subarrays With Sum

Count the non-empty subarrays of a binary array whose sum equals goal, by counting sums at most goal and at most goal - 1 with two sliding windows.

Problem Understanding

Binary Subarrays With Sum: given a binary array nums and an integer goal, return the number of non-empty contiguous subarrays whose sum is goal.

Examples: [1,0,1,0,1], goal 2 → 4; [0,0,0,0,0], goal 0 → 15.

The Intuition: Exactly = At Most − At Most

Counting "sum at most g" is a textbook sliding window: grow on the right, shrink on the left while the sum is too big, and every window ending at right inside the current one counts. Then:

  1. atMost(goal) counts subarrays with sum 0, 1, …, goal.
  2. atMost(goal − 1) counts sum 0, 1, …, goal − 1.
  3. The difference is exactly the subarrays with sum goal.

The same shrink-while-invalid window drives Max Consecutive Ones III, and the prefix-sum alternative is Subarray Sum Equals K.

Interactive Walkthrough

GOAL 2 · atMost(2) − atMost(1)

EXACTLY = AT MOST − AT MOST

pass 1: sum ≤ 2

1

0

0

1

1

2

0

3

1

4

sum

:

count

:

answer

:

 

Exactly 2 = (subarrays with sum ≤ 2) − (subarrays with sum ≤ 1)

Next

atMost(2): count subarrays whose sum is at most 2

Free preview: the first 9 of 30 steps

nums

goal

The run makes two passes. On each count step the shaded window is exactly the set of starting points counted for subarrays ending at R. Try Example 2 to see atMost(−1) return 0.

Dry Run Table

Input: [1,0,1,0,1], goal 2.

Pass Counts per right Total
atMost(2) 1, 2, 3, 4, 4 14
atMost(1) 1, 2, 2, 3, 2 10

Answer: 14 − 10 = 4.

The Solution Template

A helper for at most g, called twice.

Binary Subarrays With Sum Code
1var numSubarraysWithSum = function(nums, goal) {
2 const atMost = (g) => {
3 if (g < 0) return 0;
4 let left = 0, sum = 0, count = 0;
5 for (let right = 0; right < nums.length; right++) {
6 sum += nums[right];
7 while (sum > g) sum -= nums[left++];
8 count += right - left + 1;
9 }
10 return count;
11 };
12 return atMost(goal) - atMost(goal - 1);
13};

Edge Cases & Common Mistakes

  • goal = 0: atMost(−1) must return 0, not loop forever.
  • goal larger than the total: both passes count everything; the answer is 0.
  • All zeros: every subarray has sum 0: n(n + 1) / 2.
  • Counting only when sum == goal: misses windows that differ only by zeros.
  • Negative numbers: the window method breaks; use prefix sums instead.

Summary

Count subarrays with sum at most g using a shrinking window that adds right − left + 1 per step, and return atMost(goal) − atMost(goal − 1). O(n) time, O(1) space.

More practice: DSA interview questions with answers · patterns cheat sheet

The approach, step by step

  1. Write atMost(g)

    Slide a window: add nums[right], shrink from the left while the sum exceeds g, and add right - left + 1 to the count.

  2. Handle negatives

    atMost of a negative g is 0.

  3. Subtract

    Return atMost(goal) - atMost(goal - 1).

Frequently asked questions

Why not use one sliding window for 'exactly goal'?

A window can only count subarrays correctly if adding elements never makes a bad window good again. With zeros, a window at exactly goal can extend through zeros and stay at goal, and it can lose a leading zero and still be at goal, so there is no single left boundary to track. 'At most g' does have that property: once the sum is over g, every larger window is over too.


Why does atMost count right - left + 1?

After shrinking, [left, right] is the longest window ending at right with sum at most g. Every shorter window ending at right has an equal or smaller sum, so all right - left + 1 subarrays starting between left and right qualify.


What about a prefix-sum hash map?

Also O(n): keep a count of each prefix sum seen; at each index add count[prefix - goal]. It is the method from Subarray Sum Equals K and works for any integers. The two-window version uses O(1) space but needs non-negative values.


Which other problems use the same trick?

Count Number of Nice Subarrays (exactly k odd numbers) and Subarrays with K Different Integers (exactly k distinct values) are both solved as atMost(k) - atMost(k - 1).

New to the technique behind this problem? Watch it run step by step:

Sliding Window Visualization

Applying for software engineering roles? Free, no sign-up:

AI resume checker: match your resume to the job description