Indexes of Subarray Sum is a classic sliding window problem. When an array has only non-negative numbers, you can find a contiguous run that adds up to a target by growing and shrinking a single window — no nested loops needed.
Problem. Given an array of positive integers nums and a target, find a contiguous subarray
whose values sum to exactly target. Return its 1-based start and end indices [start, end]. If no
such subarray exists, return [-1].
Example: nums = [1, 2, 3, 7, 5], target = 12 → answer [2, 4] (because nums[2] + nums[3] + nums[4] in
1-based terms is 2 + 3 + 7 = 12).
The slow way first
The obvious idea: try every starting index, then extend a second loop forward adding numbers until you hit or pass the target. That works, but it is O(n²) — for each of the n starts you may scan most of the array again.
The question to ask: do I really need to recompute each window from scratch? No. When I move the right edge one step right, the new sum is just the old sum plus one number. And when the sum gets too big, I can drop numbers off the left edge instead of starting over. That reuse is what makes one pass enough.
The idea: one window, two edges
Keep a window bounded by start and end, and a running total of everything inside it. Walk end across the array. At each step:
- Expand: add
nums[end]tototal. - Shrink: while
totalis greater than the target, subtractnums[start]and movestartright. - Check: if
totalnow equals the target, the window is the answer.
Because every number is positive, growing the window can only increase the sum and shrinking can only decrease it — so this monotonic behavior is exactly what lets a single window find the answer.
The key insight: start only ever moves forward, and so does end. Each pointer travels the array at most once, so the total work is linear even though there are two loops in the code.
Walk through it
Step through the animation. end slides right adding 1, 2, 3 — the running total climbs to 6, still short of 12. Adding 7 pushes total to 13, which overshoots, so the window shrinks: we drop the leftmost 1, leaving total = 12 and start at the value 2. Now total == target, so the window [2, 3, 7] is the answer and we return its 1-based bounds [2, 4].
Pseudocode
start = 0
total = 0
for end from 0 to n-1:
total += nums[end] # expand the window to the right
while total > target: # window sum too big
total -= nums[start] # drop the leftmost number
start += 1
if total == target: # exact match
return [start + 1, end + 1] # convert to 1-based
return [-1] # no subarray foundThe Python solution
def subarray_sum(nums, target):
start = 0
total = 0
for end in range(len(nums)):
total += nums[end]
while total > target:
total -= nums[start]
start += 1
if total == target:
return [start + 1, end + 1]
return [-1]startis the left edge of the window;totalis the sum of everything currently inside it.- The
forloop drives the right edge: each iteration addsnums[end]to the window. - The
whileloop is the shrink phase — as long as the sum exceeds the target, peel numbers off the left. - Line 9 checks for an exact hit; line 10 returns the bounds, adding
1to each index to make them 1-based. - If the loop finishes without a match, we return
[-1].
Complexity
| Case | Time | Notes |
|---|---|---|
| Brute force (every window) | O(n²) (slow) | restart the sum from each index |
| Sliding window (this solution) | O(n) (moderate) | each pointer moves forward at most n times |
O(1) (fast)Even though there is a while loop inside the for loop, start advances at most n times across the whole run, so the combined work is O(n). We use only a couple of variables, so the extra space is O(1).
When this pattern shows up
When a problem asks for a contiguous subarray meeting a sum or length condition over non-negative numbers, reach for a sliding window. The tell is that growing the window changes the answer in one direction and shrinking it changes it the other way, so you can chase the target by moving two pointers.
This window trick relies on the numbers being non-negative. If the array can contain negatives, shrinking no longer reliably lowers the sum, so the window can skip the answer — use a prefix-sum hash map instead.
Practice
For nums = [1, 2, 3, 7, 5], target = 12, what does total become right after end reaches the value 7, and what happens next?
1. Why does the sliding window run in O(n) despite the nested while loop?
2. When do we shrink the window from the left?
3. Why does this approach require the numbers to be non-negative?
4. Why does the code add 1 to start and end before returning?