Binary Subarrays With Sum
Count 0/1 subarrays summing to goal — atMost(goal) − atMost(goal−1).
3 min read
sliding-window array
Problem#
Given a binary array nums and an integer goal, return the number of non-empty subarrays whose sum equals goal.
Examples#
nums = [1,0,1,0,1], goal = 2→4nums = [0,0,0,0,0], goal = 0→15
Constraints#
1 <= nums.length <= 3 * 10^4,goal <= sum(nums).
Approach#
Same exact-vs-atmost trick: exact(goal) = atMost(goal) − atMost(goal − 1). atMost(g) is a clean sliding window over binary values.
Solution#
class Solution {public: int numSubarraysWithSum(vector<int>& nums, int goal) { return atMost(nums, goal) - atMost(nums, goal - 1); }private: int atMost(vector<int>& nums, int g) { if (g < 0) return 0; int left = 0, sum = 0, ans = 0; for (int right = 0; right < (int)nums.size(); ++right) { sum += nums[right]; while (sum > g) sum -= nums[left++]; ans += right - left + 1; } return ans; }};func numSubarraysWithSum(nums []int, goal int) int { atMost := func(g int) int { if g < 0 { return 0 } left, sum, ans := 0, 0, 0 for right := 0; right < len(nums); right++ { sum += nums[right] for sum > g { sum -= nums[left] left++ } ans += right - left + 1 } return ans } return atMost(goal) - atMost(goal-1)}from typing import List
class Solution: def numSubarraysWithSum(self, nums: List[int], goal: int) -> int: def at_most(g: int) -> int: if g < 0: return 0 left = 0 total = 0 ans = 0 for right in range(len(nums)): total += nums[right] while total > g: total -= nums[left] left += 1 ans += right - left + 1 return ans
return at_most(goal) - at_most(goal - 1)var numSubarraysWithSum = function(nums, goal) { const atMost = (g) => { if (g < 0) return 0; let left = 0, sum = 0, ans = 0; for (let right = 0; right < nums.length; right++) { sum += nums[right]; while (sum > g) { sum -= nums[left]; left++; } ans += right - left + 1; } return ans; }; return atMost(goal) - atMost(goal - 1);};class Solution { public int numSubarraysWithSum(int[] nums, int goal) { return atMost(nums, goal) - atMost(nums, goal - 1); }
private int atMost(int[] nums, int g) { if (g < 0) return 0; int left = 0, sum = 0, ans = 0; for (int right = 0; right < nums.length; right++) { sum += nums[right]; while (sum > g) { sum -= nums[left]; left++; } ans += right - left + 1; } return ans; }}function numSubarraysWithSum(nums: number[], goal: number): number { const atMost = (g: number): number => { if (g < 0) return 0; let left = 0, sum = 0, ans = 0; for (let right = 0; right < nums.length; right++) { sum += nums[right]; while (sum > g) { sum -= nums[left]; left++; } ans += right - left + 1; } return ans; }; return atMost(goal) - atMost(goal - 1);}Editorial#
The presence of zeros prevents the naïve sliding window from working for “exactly K” — zeros can be padded indefinitely. The atMost difference reduction reduces both cases to monotone windows, which handle zeros naturally.
Complexity#
- Time: O(n).
- Space: O(1).
Concept revision#
Related#