🧠
Two Pointers / Sliding Window for Binary Arrays
💡 This approach uses two sliding windows to count subarrays with sum exactly equal to goal by counting subarrays with sum at most goal and at most goal-1.
Intuition
Count subarrays with sum ≤ goal and subtract those with sum ≤ goal-1 to get count of subarrays with sum exactly goal.
Algorithm
- Define a helper function to count subarrays with sum at most S using two pointers.
- Use this helper to count subarrays with sum ≤ goal and sum ≤ goal-1.
- Return the difference of these two counts as the final answer.
💡 The key insight is that counting subarrays with sum exactly goal is equivalent to difference of counts of subarrays with sum at most goal and at most goal-1.
def numSubarraysWithSum(nums, goal):
def atMost(S):
count = left = 0
current_sum = 0
for right, num in enumerate(nums):
current_sum += num
while current_sum > S:
current_sum -= nums[left]
left += 1
count += right - left + 1
return count
return atMost(goal) - atMost(goal - 1) if goal > 0 else atMost(0)
# Driver code
if __name__ == '__main__':
print(numSubarraysWithSum([1,0,1,0,1], 2)) # Output: 4
Line Notes
def atMost(S):Helper counts subarrays with sum at most S
while current_sum > S:Shrink window from left until sum ≤ S
count += right - left + 1Add number of valid subarrays ending at right
return atMost(goal) - atMost(goal - 1)Difference gives count of subarrays with sum exactly goal
public class Solution {
private static int atMost(int[] nums, int S) {
int count = 0, left = 0, currentSum = 0;
for (int right = 0; right < nums.length; right++) {
currentSum += nums[right];
while (currentSum > S) {
currentSum -= nums[left++];
}
count += right - left + 1;
}
return count;
}
public static int numSubarraysWithSum(int[] nums, int goal) {
if (goal == 0) return atMost(nums, 0);
return atMost(nums, goal) - atMost(nums, goal - 1);
}
public static void main(String[] args) {
System.out.println(numSubarraysWithSum(new int[]{1,0,1,0,1}, 2)); // Output: 4
}
}
Line Notes
private static int atMost(int[] nums, int S)Helper counts subarrays with sum at most S
while (currentSum > S)Shrink window from left to maintain sum ≤ S
count += right - left + 1;Add count of valid subarrays ending at right
return atMost(nums, goal) - atMost(nums, goal - 1);Difference yields exact count of subarrays with sum goal
#include <iostream>
#include <vector>
using namespace std;
int atMost(const vector<int>& nums, int S) {
int count = 0, left = 0, currentSum = 0;
for (int right = 0; right < (int)nums.size(); right++) {
currentSum += nums[right];
while (currentSum > S) {
currentSum -= nums[left++];
}
count += right - left + 1;
}
return count;
}
int numSubarraysWithSum(vector<int>& nums, int goal) {
if (goal == 0) return atMost(nums, 0);
return atMost(nums, goal) - atMost(nums, goal - 1);
}
int main() {
vector<int> nums = {1,0,1,0,1};
cout << numSubarraysWithSum(nums, 2) << endl; // Output: 4
return 0;
}
Line Notes
int atMost(const vector<int>& nums, int S)Helper function counts subarrays with sum ≤ S
while (currentSum > S)Shrink window from left to keep sum ≤ S
count += right - left + 1;Add count of valid subarrays ending at right
return atMost(nums, goal) - atMost(nums, goal - 1);Difference gives count of subarrays with sum exactly goal
function numSubarraysWithSum(nums, goal) {
function atMost(S) {
let count = 0, left = 0, currentSum = 0;
for (let right = 0; right < nums.length; right++) {
currentSum += nums[right];
while (currentSum > S) {
currentSum -= nums[left++];
}
count += right - left + 1;
}
return count;
}
if (goal === 0) return atMost(0);
return atMost(goal) - atMost(goal - 1);
}
// Test
console.log(numSubarraysWithSum([1,0,1,0,1], 2)); // Output: 4
Line Notes
function atMost(S)Helper counts subarrays with sum at most S
while (currentSum > S)Shrink window from left to maintain sum ≤ S
count += right - left + 1;Add count of valid subarrays ending at right
return atMost(goal) - atMost(goal - 1);Difference yields exact count of subarrays with sum goal
Each element is visited at most twice by the two pointers, and only constant extra space is used.
💡 For n=100000, this means about 200000 operations, very efficient and uses minimal memory.
Interview Verdict: Accepted
This approach is optimal in time and space for this problem and is a great demonstration of sliding window technique.