Chapter 3: Mathematical Foundations for DSA
3.02Beginner7 topics16 min4 interactive animations

Summations and sequences

Sums and sequences are how running times are added up. This lesson covers arithmetic and geometric progressions, closed formulas, prefix sums, the harmonic series, telescoping sums and the Fibonacci sequence.

Learning goals

  • Evaluate arithmetic and geometric sums in closed form
  • Use prefix sums for range queries
  • Recognise the harmonic series in loop analysis
  • Compute Fibonacci numbers efficiently and safely

Prerequisites

Arithmetic essentials
3.02.1

Arithmetic progression

An arithmetic progression has a constant difference d: a, a + d, a + 2d, …. Its sum is the number of terms times the average of the first and last: S = n(a + l) / 2. For 1 + 2 + … + n this is n(n + 1) / 2, which is why a nested loop where the inner bound grows by one is O(n²).

Gauss paired the first and last terms, which each sum to n + 1. Step through the pairing.

Gauss's trick: 1 + 2 + … + n

Interactive · edit the input

Your input

Try

int[] arr · length 10

1
2
3
4
5
6
7
8
9
10
0123456789
Being comparedPairedPaired

pair sums

1+10=11
2+9=11
3+8=11
4+7=11
5+6=11

running total

0
Setup

Add 10 numbers one by one and you do 10 additions. Gauss noticed that numbers equidistant from the two ends always add to the same value, n + 1 = 11.

Step 1 / 7
Java
1static long sumTo(int n) { // 1 + 2 + ... + n
2 long total = 0;
3 for (int i = 1; i <= n; i++) total += i; // n additions
4 return total;
5}
6
7static long sumToFormula(int n) {
8 return (long) n * (n + 1) / 2; // n/2 pairs, each summing to n + 1
9}

Live state

0 additions

n

10

No condition evaluated on this step
Execution trace (dry run table)Show 7 steps
StepLineStateWhat happens
1L1n=10Add 10 numbers one by one and you do 10 additions. Gauss noticed that numbers equidistant from the two ends always add to the same value, n + 1 = 11.
2L8lo=1 hi=10 pair=11 total=111 + 10 = 11. Pair the next two from the ends: every pair equals n + 1.
3L8lo=2 hi=9 pair=11 total=222 + 9 = 11. Pair the next two from the ends: every pair equals n + 1.
4L8lo=3 hi=8 pair=11 total=333 + 8 = 11. Pair the next two from the ends: every pair equals n + 1.
5L8lo=4 hi=7 pair=11 total=444 + 7 = 11. Pair the next two from the ends: every pair equals n + 1.
6L8lo=5 hi=6 pair=11 total=555 + 6 = 11. Pair the next two from the ends: every pair equals n + 1.
7L8n(n+1)/2=55 total=55 return=5510 × 11 / 2 = 55, the same as the loop's total 55. The loop is O(n); the formula is O(1). Use long: n(n + 1) overflows int for n above about 46,340.
3.02.2

Geometric progression

A geometric progression multiplies by a ratio r: a, ar, ar², …. The sum of n terms is a(rⁿ - 1) / (r - 1) for r ≠ 1. With r = 2: 1 + 2 + 4 + … + 2ᵏ⁻¹ = 2ᵏ - 1, so the total work in the last level of a binary tree is about the same as all the levels above it combined.

For |r| < 1 the infinite sum converges to a / (1 - r); for example n + n/2 + n/4 + … < 2n, which explains why halving costs total O(n).

SeriesClosed formOrder
1 + 2 + 4 + … + 2ᵏ2ᵏ⁺¹ - 1Θ(2ᵏ)
n + n/2 + n/4 + …< 2nΘ(n)
1 + 3 + 9 + … + 3ᵏ(3ᵏ⁺¹ - 1) / 2Θ(3ᵏ)
3.02.3

Sum formulas

Three formulas cover most loop analysis: Σi = n(n + 1)/2, Σi² = n(n + 1)(2n + 1)/6 and Σi³ = (n(n + 1)/2)². They show that a triple loop whose bounds grow is Θ(n³), and that Σi² grows like n³/3.

Check any formula with small n before relying on it: Σi² for n = 4 is 1 + 4 + 9 + 16 = 30 and 4·5·9/6 = 30. Use long when n is large because n(n + 1) overflows int above about 46,340.

Java
1long n = 100_000;
2long sum = n * (n + 1) / 2; // 5000050000
3long sumSq = n * (n + 1) * (2 * n + 1) / 6; // 333338333350000

Gauss's trick: 1 + 2 + … + n

Interactive · edit the input

Your input

Try

int[] arr · length 10

1
2
3
4
5
6
7
8
9
10
0123456789
Being comparedPairedPaired

pair sums

1+10=11
2+9=11
3+8=11
4+7=11
5+6=11

running total

0
Setup

Add 10 numbers one by one and you do 10 additions. Gauss noticed that numbers equidistant from the two ends always add to the same value, n + 1 = 11.

Step 1 / 7
Java
1static long sumTo(int n) { // 1 + 2 + ... + n
2 long total = 0;
3 for (int i = 1; i <= n; i++) total += i; // n additions
4 return total;
5}
6
7static long sumToFormula(int n) {
8 return (long) n * (n + 1) / 2; // n/2 pairs, each summing to n + 1
9}

Live state

0 additions

n

10

No condition evaluated on this step
Execution trace (dry run table)Show 7 steps
StepLineStateWhat happens
1L1n=10Add 10 numbers one by one and you do 10 additions. Gauss noticed that numbers equidistant from the two ends always add to the same value, n + 1 = 11.
2L8lo=1 hi=10 pair=11 total=111 + 10 = 11. Pair the next two from the ends: every pair equals n + 1.
3L8lo=2 hi=9 pair=11 total=222 + 9 = 11. Pair the next two from the ends: every pair equals n + 1.
4L8lo=3 hi=8 pair=11 total=333 + 8 = 11. Pair the next two from the ends: every pair equals n + 1.
5L8lo=4 hi=7 pair=11 total=444 + 7 = 11. Pair the next two from the ends: every pair equals n + 1.
6L8lo=5 hi=6 pair=11 total=555 + 6 = 11. Pair the next two from the ends: every pair equals n + 1.
7L8n(n+1)/2=55 total=55 return=5510 × 11 / 2 = 55, the same as the loop's total 55. The loop is O(n); the formula is O(1). Use long: n(n + 1) overflows int for n above about 46,340.
3.02.4

Prefix sums

A prefix-sum array stores p[i] = sum of the first i elements. Any range sum then costs O(1): sum(l..r) = p[r + 1] - p[l]. Building takes O(n), so q queries cost O(n + q) rather than O(nq).

Change the array and query range in the animation to see the subtraction.

Java
1int[] a = {3, 1, 4, 1, 5};
2long[] p = new long[a.length + 1];
3for (int i = 0; i < a.length; i++) p[i + 1] = p[i] + a[i]; // [0, 3, 4, 8, 9, 14]
4long range = p[4] - p[1]; // sum of a[1..3] = 1 + 4 + 1 = 6

Prefix sums and O(1) range queries

Interactive · edit the input

Your input

Try

int[] arr · length 8

3
-1
4
1
5
9
-2
6
01234567
Being comparedIn the query rangeAlready checked

prefix[]

00
·1
·2
·3
·4
·5
·6
·7
·8
Setup

prefix has n + 1 slots. prefix[0] = 0 is the sum of nothing, which removes every special case for l = 0.

Step 1 / 10
Java
1static int[] buildPrefix(int[] arr) {
2 int[] prefix = new int[arr.length + 1]; // prefix[i] = arr[0] + ... + arr[i-1]
3 for (int i = 0; i < arr.length; i++) {
4 prefix[i + 1] = prefix[i] + arr[i];
5 }
6 return prefix;
7}
8
9static int rangeSum(int[] prefix, int l, int r) { // sum of arr[l..r]
10 return prefix[r + 1] - prefix[l];
11}

Live state

0 additions

n

8

No condition evaluated on this step
Execution trace (dry run table)Show 10 steps
StepLineStateWhat happens
1L2n=8prefix has n + 1 slots. prefix[0] = 0 is the sum of nothing, which removes every special case for l = 0.
2L4i=0 arr[i]=3 prefix[i+1]=3prefix[1] = prefix[0] + arr[0] = 0 + 3 = 3.
3L4i=1 arr[i]=-1 prefix[i+1]=2prefix[2] = prefix[1] + arr[1] = 3 + -1 = 2.
4L4i=2 arr[i]=4 prefix[i+1]=6prefix[3] = prefix[2] + arr[2] = 2 + 4 = 6.
5L4i=3 arr[i]=1 prefix[i+1]=7prefix[4] = prefix[3] + arr[3] = 6 + 1 = 7.
6L4i=4 arr[i]=5 prefix[i+1]=12prefix[5] = prefix[4] + arr[4] = 7 + 5 = 12.
7L4i=5 arr[i]=9 prefix[i+1]=21prefix[6] = prefix[5] + arr[5] = 12 + 9 = 21.
8L4i=6 arr[i]=-2 prefix[i+1]=19prefix[7] = prefix[6] + arr[6] = 21 + -2 = 19.
9L4i=7 arr[i]=6 prefix[i+1]=25prefix[8] = prefix[7] + arr[7] = 19 + 6 = 25.
10L10l=2 r=5 prefix[r+1]=21 prefix[l]=2 return=19Sum of arr[2..5] = prefix[6] - prefix[2] = 21 - 2 = 19. Building took O(n) once; every query afterwards is O(1).
3.02.5

Harmonic series

The harmonic series Hₙ = 1 + 1/2 + 1/3 + … + 1/n grows like ln n + 0.5772 (so about 14.4 at n = 10⁶). It shows up in loops such as for i in 1..n: for j = i; j <= n; j += i, which run n/1 + n/2 + … + n/n = n·Hₙ = O(n log n) steps. The sieve of Eratosthenes has the same structure.

Because Hₙ grows so slowly, n·Hₙ is only a little more than n.

Java
1int n = 1_000_000; long steps = 0;
2for (int i = 1; i <= n; i++) for (int j = i; j <= n; j += i) steps++;
3// steps = 13970034 = about n * (ln n + 0.577) = 1e6 * 14.39
3.02.6

Telescoping sums

A telescoping sum has terms that cancel in pairs, leaving only the ends. Since 1/(i(i + 1)) = 1/i - 1/(i + 1), the sum over i = 1..n equals 1 - 1/(n + 1). Differences in a prefix-sum array telescope in the same way: Σ(p[i + 1] - p[i]) = p[n] - p[0].

Look for a term that can be written as f(i) - f(i + 1).

Java
1// sum_{i=1..n} 1/(i(i+1)) = 1 - 1/(n+1)
2int n = 9;
3double s = 0;
4for (int i = 1; i <= n; i++) s += 1.0 / (i * (i + 1));
5// s = 0.9 = 1 - 1/10
3.02.7

Fibonacci sequence

F(0) = 0, F(1) = 1, F(n) = F(n - 1) + F(n - 2): 0, 1, 1, 2, 3, 5, 8, 13, …. Naive recursion repeats work exponentially; memoisation or a simple loop computes F(n) in O(n) time and O(1) space. F(92) = 7,540,113,804,746,346,429 is the largest value that fits in long.

Compare the call counts with and without memoisation in the animation.

Java
1static long fib(int n) { // valid for n <= 92
2 long a = 0, b = 1;
3 for (int i = 0; i < n; i++) { long t = a + b; a = b; b = t; }
4 return a;
5}

Fibonacci with memoization

Interactive · edit the input

Your input

Try

Recursion tree · 1 call

fib(6)…
Running now
Call

Call fib(6).

Step 1 / 52
Java
1static long[] memo = new long[100];
2static long fib(int n) {
3 if (n <= 1) return n; // base cases
4 if (memo[n] != 0) return memo[n]; // already solved: reuse it
5 return memo[n] = fib(n - 1) + fib(n - 2); // solve once, remember
6}

Live state

1 calls

n

6

depth

1

No condition evaluated on this step

Call stack (top first)

  1. fib(6)
Execution trace (dry run table)Show 52 steps
StepLineStateWhat happens
1L2n=6 depth=1Call fib(6).
2L3n=6Not a base case.
3L4n=6 memo[n]=0memo[6] is empty, so compute it.
4L5n=6fib(6) = fib(5) + fib(4). Call fib(5) first.
5L2n=5 depth=2Call fib(5).
6L3n=5Not a base case.
7L4n=5 memo[n]=0memo[5] is empty, so compute it.
8L5n=5fib(5) = fib(4) + fib(3). Call fib(4) first.
9L2n=4 depth=3Call fib(4).
10L3n=4Not a base case.
11L4n=4 memo[n]=0memo[4] is empty, so compute it.
12L5n=4fib(4) = fib(3) + fib(2). Call fib(3) first.
13L2n=3 depth=4Call fib(3).
14L3n=3Not a base case.
15L4n=3 memo[n]=0memo[3] is empty, so compute it.
16L5n=3fib(3) = fib(2) + fib(1). Call fib(2) first.
17L2n=2 depth=5Call fib(2).
18L3n=2Not a base case.
19L4n=2 memo[n]=0memo[2] is empty, so compute it.
20L5n=2fib(2) = fib(1) + fib(0). Call fib(1) first.
21L2n=1 depth=6Call fib(1).
22L3n=1Base case: fib(1) = 1.
23L3n=1 return=1return 1.
24L5n=2 left=1fib(1) = 1. Now call fib(0).
25L2n=0 depth=6Call fib(0).
26L3n=0Base case: fib(0) = 0.
27L3n=0 return=0return 0.
28L5n=2 left=1 right=0 return=1fib(2) = 1 + 0 = 1. Store it in memo[2].
29L5n=3 left=1fib(2) = 1. Now call fib(1).
30L2n=1 depth=5Call fib(1).
31L3n=1Base case: fib(1) = 1.
32L3n=1 return=1return 1.
33L5n=3 left=1 right=1 return=2fib(3) = 1 + 1 = 2. Store it in memo[3].
34L5n=4 left=2fib(3) = 2. Now call fib(2).
35L2n=2 depth=4Call fib(2).
36L3n=2Not a base case.
37L4n=2 memo[n]=1memo[2] is already 1. No need to recurse again.
38L4n=2 return=1Cache hit: return 1 immediately. This whole subtree is skipped.
39L5n=4 left=2 right=1 return=3fib(4) = 2 + 1 = 3. Store it in memo[4].
40L5n=5 left=3fib(4) = 3. Now call fib(3).
41L2n=3 depth=3Call fib(3).
42L3n=3Not a base case.
43L4n=3 memo[n]=2memo[3] is already 2. No need to recurse again.
44L4n=3 return=2Cache hit: return 2 immediately. This whole subtree is skipped.
45L5n=5 left=3 right=2 return=5fib(5) = 3 + 2 = 5. Store it in memo[5].
46L5n=6 left=5fib(5) = 5. Now call fib(4).
47L2n=4 depth=2Call fib(4).
48L3n=4Not a base case.
49L4n=4 memo[n]=3memo[4] is already 3. No need to recurse again.
50L4n=4 return=3Cache hit: return 3 immediately. This whole subtree is skipped.
51L5n=6 left=5 right=3 return=8fib(6) = 5 + 3 = 8. Store it in memo[6].
52L5return=8fib(6) = 8 with 11 calls. Plain recursion would need 25 calls.

Practice ladder

Now try it yourself

Easy

  • Sum 5 + 8 + 11 + … for 20 terms
  • Compute Σi² for n = 10

Medium

  • Answer 10⁵ range-sum queries with prefix sums
  • Show that n + n/2 + n/4 + … is less than 2n

Advanced

  • Compute F(n) mod 10⁹ + 7 for n = 10¹⁸ with matrix exponentiation

Key takeaways

  • n(n + 1)/2, 2ᵏ - 1 and n·Hₙ are the three sums behind most loop analysis.
  • Prefix sums turn range sums into subtraction.
  • Fibonacci fits in long up to F(92).