Data Structuressubarrays

Subarrays - Step by Step Understanding

TT
Testlaa Team
May 1, 20266 min read

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 indexl
  • End indexr

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 subarray
  • r → 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, move r from l to n-1 (nested loops)
  • Sliding window: move l when the rule breaks, extend r when 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] → typical O(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) when s += nums[r] would work
  • nums[l:r] vs nums[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 l and r, print nums[l:r+1] and verify length = r - l + 1
  • Find longest subarray with all positive numbers

Final Thought

Subarray problems may look difficult.

But always break them into steps:

  1. Choose start
  2. Choose end
  3. Apply condition

That is it.

Tags:

ArraysSubarraysBeginner Friendly