Subarray Sums I
Problem Overview
| Attribute | Value |
|---|---|
| CSES Link | Subarray Sums I |
| Difficulty | Easy |
| Category | Sliding Window / Two Pointers |
| Time Limit | 1 second |
| Key Technique | Two Pointers on Positive Array |
Learning Goals
After solving this problem, you will be able to:
- Recognize when two-pointer sliding window applies (positive numbers only)
- Implement the expand/shrink window pattern efficiently
- Understand why positive numbers guarantee monotonic window behavior
- Count subarrays with a target sum in O(n) time
Problem Statement
Problem: Given an array of n positive integers and a target sum x, count the number of subarrays whose elements sum to exactly x.
Input:
- Line 1: Two integers
nandx(array size and target sum) - Line 2:
npositive integers (the array elements)
Output:
- A single integer: the count of subarrays with sum equal to
x
Constraints:
- 1 <= n <= 2 * 10^5
- 1 <= x <= 10^9
- 1 <= a[i] <= 10^9 (all elements are positive)
Example
Input:
5 7
2 4 1 2 7
Output:
3
Explanation:
- Subarray [2, 4, 1] has sum 2 + 4 + 1 = 7
- Subarray [4, 1, 2] has sum 4 + 1 + 2 = 7
- Subarray [7] has sum 7
- Total: 3 subarrays
Intuition: How to Think About This Problem
Pattern Recognition
Key Question: All elements are positive. What does this guarantee about subarray sums?
When all elements are positive:
- Adding an element to a window always increases the sum
- Removing an element from a window always decreases the sum
- This monotonic behavior means we never need to backtrack
Breaking Down the Problem
- What are we looking for? Count of contiguous subarrays summing to exactly
x - What information do we have? Array of positive integers
- What’s the key insight? Since elements are positive, if current sum exceeds target, we must shrink the window (expanding cannot help)
Analogy
Think of filling a bucket with water:
- Each element is a cup of water (always positive amount)
- If the bucket overflows (sum > target), you must pour some out (shrink left)
- If it’s not full enough (sum < target), add more water (expand right)
Solution 1: Brute Force
Idea
Check every possible subarray and count those with sum equal to target.
Algorithm
- For each starting index
i - For each ending index
j >= i - Calculate sum of subarray [i, j]
- If sum equals target, increment count
Code
def count_subarrays_brute(n, x, arr):
"""
Brute force: check all subarrays.
Time: O(n^2), Space: O(1)
"""
count = 0
for i in range(n):
current_sum = 0
for j in range(i, n):
current_sum += arr[j]
if current_sum == x:
count += 1
elif current_sum > x:
break # Optimization: sum can only increase
return count
Complexity
| Metric | Value | Explanation |
|---|---|---|
| Time | O(n^2) | Nested loops over array |
| Space | O(1) | Only tracking sum and count |
Why This Works (But Is Slow)
Correctness is guaranteed because we check every subarray. However, O(n^2) is too slow for n = 2*10^5.
Solution 2: Two Pointers (Optimal)
Key Insight
The Trick: Since all elements are positive, we can use a sliding window. Expand right to increase sum, shrink left to decrease sum. Each element is added and removed at most once.
Algorithm
- Initialize
left = 0,current_sum = 0,count = 0 - For each
rightfrom 0 to n-1:- Add
arr[right]tocurrent_sum - While
current_sum > x: subtractarr[left]and incrementleft - If
current_sum == x: incrementcount
- Add
- Return
count
Why Two Pointers Works Here
| Property | Guaranteed By |
|---|---|
| Sum increases when expanding | All elements positive |
| Sum decreases when shrinking | All elements positive |
| Never need to expand left | Monotonic sum behavior |
| Each element visited at most twice | Left pointer only moves right |
Dry Run Example
Input: n = 5, x = 7, arr = [2, 4, 1, 2, 7]
Initial: left = 0, sum = 0, count = 0
Step 1: right = 0, add arr[0] = 2
sum = 2
2 < 7, no shrink
2 != 7, no count
Window: [2]
Step 2: right = 1, add arr[1] = 4
sum = 6
6 < 7, no shrink
6 != 7, no count
Window: [2, 4]
Step 3: right = 2, add arr[2] = 1
sum = 7
7 = 7, no shrink
7 == 7, count = 1 <-- Found [2, 4, 1]
Window: [2, 4, 1]
Step 4: right = 3, add arr[3] = 2
sum = 9
9 > 7, shrink: sum -= arr[0]=2, left = 1, sum = 7
7 = 7, stop shrinking
7 == 7, count = 2 <-- Found [4, 1, 2]
Window: [4, 1, 2]
Step 5: right = 4, add arr[4] = 7
sum = 14
14 > 7, shrink: sum -= arr[1]=4, left = 2, sum = 10
10 > 7, shrink: sum -= arr[2]=1, left = 3, sum = 9
9 > 7, shrink: sum -= arr[3]=2, left = 4, sum = 7
7 == 7, count = 3 <-- Found [7]
Window: [7]
Result: count = 3
All three subarrays found: [2,4,1], [4,1,2], and [7], each summing to 7.
Visual Diagram
arr: [2, 4, 1, 2, 7]
index: 0 1 2 3 4
Window evolution (target = 7):
[2] sum=2 < 7, expand
[2,4] sum=6 < 7, expand
[2,4,1] sum=7 = 7, COUNT!
[2,4,1,2] sum=9 > 7, shrink
[4,1,2] sum=7 = 7, COUNT!
[4,1,2,7] sum=14 > 7, shrink
[1,2,7] sum=10 > 7, shrink
[2,7] sum=9 > 7, shrink
[7] sum=7 = 7, COUNT!
Code
def count_subarrays(n, x, arr):
"""
Two-pointer sliding window for positive arrays.
Time: O(n), Space: O(1)
"""
count = 0
current_sum = 0
left = 0
for right in range(n):
current_sum += arr[right]
# Shrink window while sum exceeds target
while current_sum > x and left <= right:
current_sum -= arr[left]
left += 1
# Check if current window matches target
if current_sum == x:
count += 1
return count
# Main
if __name__ == "__main__":
n, x = map(int, input().split())
arr = list(map(int, input().split()))
print(count_subarrays(n, x, arr))
Complexity
| Metric | Value | Explanation |
|---|---|---|
| Time | O(n) | Each element added once, removed at most once |
| Space | O(1) | Only pointers and sum variables |
Common Mistakes
Mistake 1: Forgetting the Positive Constraint
# WRONG approach for arrays with negative numbers
# Two pointers does NOT work when elements can be negative!
# Use hash map approach for Subarray Sums II instead
Problem: If array has negatives, shrinking window might not decrease sum. Fix: Verify constraint says “positive integers” before using two pointers.
Mistake 2: Integer Overflow
Problem: Sum can reach 2*10^14, exceeding int range.
Fix: Use long long for sum and count in C++.
Mistake 3: Off-by-One in Window Shrinking
# WRONG
while current_sum > x:
current_sum -= arr[left]
left += 1
# If left > right, we access invalid elements next iteration
# CORRECT
while current_sum > x and left <= right:
current_sum -= arr[left]
left += 1
Problem: Window can become empty, causing issues.
Fix: Add boundary check left <= right.
Mistake 4: Not Handling Empty Result
# The algorithm naturally handles no matches (returns 0)
# But ensure you don't print "IMPOSSIBLE" - just print 0
Edge Cases
| Case | Input | Expected Output | Why |
|---|---|---|---|
| Single element match | 1 5 / 5 |
1 |
Subarray [5] |
| No matches | 3 100 / 1 2 3 |
0 |
No subarray sums to 100 |
| All same elements | 4 6 / 2 2 2 2 |
2 |
[2,2,2] appears twice |
| Entire array | 3 6 / 1 2 3 |
1 |
Whole array sums to target |
| Large values | 2 2000000000 / 10^9 10^9 |
1 |
Tests long long handling |
| Single element array | 1 1 / 1 |
1 |
Simplest valid case |
When to Use This Pattern
Use Two Pointers / Sliding Window When:
- All array elements are positive (or non-negative with care)
- Looking for subarrays with exact/at-most/at-least sum
- Need O(n) time complexity
- Can tolerate O(1) extra space
Don’t Use When:
- Array contains negative numbers (use hash map - see Subarray Sums II)
- Need to find ALL subarrays, not just count
- Problem asks for non-contiguous subsequences
Pattern Recognition Checklist:
- Contiguous subarray problem? --> Consider sliding window
- All positive elements? --> Two pointers works
- Target is exact sum? --> Track when sum equals target
- Elements can be negative? --> Use prefix sum + hash map instead
Related Problems
CSES Problems
| Problem | Link | Key Difference |
|---|---|---|
| Subarray Sums II | Task 1661 | Allows negative numbers (use hash map) |
| Subarray Divisibility | Task 1662 | Sum divisible by n (prefix sum modulo) |
| Maximum Subarray Sum | Task 1643 | Find max sum (Kadane’s algorithm) |
Similar Patterns
| Problem | Platform | Technique |
|---|---|---|
| Minimum Size Subarray Sum | LeetCode 209 | Two pointers, find min length |
| Subarray Product Less Than K | LeetCode 713 | Two pointers with product |
| Longest Substring Without Repeating | LeetCode 3 | Sliding window with set |
Key Takeaways
- The Core Idea: Positive elements guarantee monotonic sum behavior, enabling O(n) two-pointer solution
- Time Optimization: From O(n^2) brute force to O(n) sliding window
- Space Trade-off: No extra space needed beyond pointers
- Critical Check: This technique ONLY works for positive arrays - verify constraints!
Practice Checklist
Before moving on, make sure you can:
- Explain why two pointers works for positive arrays but not negative
- Trace through the algorithm on paper without code
- Implement the solution from scratch in under 10 minutes
- Identify this pattern when seeing similar problems
- Know when to use hash map approach instead (Subarray Sums II)