Subarrays - Step by Step Understanding
First, What is a Subarray?
Let us start very simple.
nums = [10, 20, 30]
From this array, we can take continuous parts.
These parts are called subarrays.
Important Rule
A subarray must be continuous.
Correct subarrays:
[10][20][30][10, 20][20, 30][10, 20, 30]
Not a subarray:
[10, 30](because 20 is skipped)
How Do We Form a Subarray?
We always choose:
- Start index →
l - End index →
r
Everything between them is the subarray.
Example:
nums = [10, 20, 30, 40]
l = 1
r = 3
Subarray is:
[20, 30, 40]
Because:
- Start at index
1 - End at index
r
Length of a Subarray
Formula:
length = r - l + 1
Example:
l = 1
r = 3
length = 3 - 1 + 1 = 3
Subarray indexing - subarray_indexing
Subarray indexing means: you name and maintain the two boundaries that define a contiguous window.
The two boundaries (inclusive)
l→ first index inside the subarrayr→ last index inside the subarray
Everything from l to r (inclusive) is your subarray.
Length (same rule everywhere)
length = r - l + 1
Python: loop vs slice (easy off-by-one)
Loops usually need r + 1 because range end is exclusive:
for i in range(l, r + 1):
print(nums[i])
Slices also end exclusive, so the inclusive window is:
window = nums[l : r + 1]
A common bug is writing nums[l:r] and accidentally dropping nums[r].
Valid bounds
For n = len(nums) you normally need:
0 <= l <= r < n
If l > r, the window is empty (sometimes useful as a starting state - define what your problem expects).
Managing boundaries in algorithms
Typical patterns:
- Enumerate: fix
l, moverfromlton-1(nested loops) - Sliding window: move
lwhen the rule breaks, extendrwhen the rule allows
Pick one convention (here: l and r inclusive) and stick to it - mixed “inclusive/exclusive r” is the main source of bugs.
Listing All Subarrays (Very Important)
Let us take:
nums = [1, 2, 3]
All subarrays:
[1][1, 2][1, 2, 3][2][2, 3][3]
How Do We Generate Them in Code?
nums = [1, 2, 3]
for l in range(len(nums)):
for r in range(l, len(nums)):
print(nums[l:r+1])
Explanation:
- First loop → starting point
l - Second loop → ending point
r
This prints all subarrays.
Subarray sum analysis - subarray_sum_analysis
Subarray sum analysis means: understand how sums change as you move l and r, and pick a method that is fast enough for the task.
Example sums (small array)
nums = [1, 2, 3]
Subarrays and their sums:
[1]→ 1[1, 2]→ 3[1, 2, 3]→ 6[2]→ 2[2, 3]→ 5[3]→ 3
One sum for a fixed (l, r) (direct loop)
l = 0
r = 2
s = 0
for i in range(l, r + 1):
s += nums[i]
print(s)
Level 1 - naive “re-sum every window” (slow)
A common beginner pattern is three nested loops (re-scan from l to r each time):
nums = [1, 2, 3]
n = len(nums)
for l in range(n):
for r in range(l, n):
s = 0
for i in range(l, r + 1):
s += nums[i]
# analyze s here (print, compare, count, etc.)
Rough time: about O(n³) for all pairs - fine for tiny arrays, too slow for large n.
Level 2 - incremental sum while extending r (much better)
Key observation: for a fixed l, when r increases by 1, the sum grows by nums[r] only.
nums = [1, 2, 3]
n = len(nums)
for l in range(n):
s = 0
for r in range(l, n):
s += nums[r]
# analyze s for subarray nums[l … r]
This is the usual O(n²) “enumerate all subarrays by sum” template.
new_sum_for_same_l = old_sum + nums[r]
Level 3 - many range-sum questions on the same array (prefix sums)
If the array does not change and you need many queries of the form “sum from l to r”:
- Build a prefix sum array once (
O(n)) - Answer each query in
O(1)using subtraction
That full treatment lives on:
/resources/arrays/prefix-sum
Mindset
Analysis = choose the right tool:
- Brute re-sum → simple, usually
O(n³)over all windows - Incremental
s += nums[r]→ typicalO(n²)enumeration - Prefix sums → best when you need repeated range sums on a static array
Counting Subarrays
Sometimes the question asks:
“How many subarrays satisfy a condition?”
Example: Count subarrays with sum > 3.
nums = [1, 2, 3]
count = 0
for l in range(len(nums)):
s = 0
for r in range(l, len(nums)):
s += nums[r]
if s > 3:
count += 1
print(count)
Longest Subarray (Very Important Pattern)
The question is often:
“Find the longest subarray that satisfies a condition.”
Example:
nums = [1, 2, -1, 2, 3]
Suppose we want: find longest subarray with positive sum.
Idea:
- Start from left
- Expand to the right
- If condition fails → move left
This is a sliding window idea (you will learn more later).
Key Understanding
Subarrays are always:
- Continuous
- Defined by
(l, r)with clear inclusive indexing (subarray_indexing)
Used for:
- Sum analysis (
subarray_sum_analysis) - compute / compare / count sums efficiently - Count problems
- Longest segment problems
Common Mistakes
- Thinking subarray = any combination (wrong)
- Forgetting continuity
- Confusing with subsequence
- Re-summing every
(l, r)from scratch inside nested loops (O(n³)trap) whens += nums[r]would work nums[l:r]vsnums[l:r+1]confusion
Practice (Must Try)
- List all subarrays of
[2, 4, 6] - Count subarrays with sum > 5
- Rewrite a triple nested sum loop as
s += nums[r]and explain why it is faster - Find subarrays of length 2
- Given
landr, printnums[l:r+1]and verifylength = r - l + 1 - Find longest subarray with all positive numbers
Final Thought
Subarray problems may look difficult.
But always break them into steps:
- Choose start
- Choose end
- Apply condition
That is it.
