int sum(int a, int b) { int result = a + b; return result; }
Below you will find seventeen short programs, arranged in four levels of difficulty. For each one, your task is to determine the worst-case time complexity in Big-O notation.
Read carefully. Count the loops. Watch what changes — and how quickly — between iterations. Recursive functions ask you to think in terms of recurrence relations: T(n) = aT(n/b) + f(n).
Resist the temptation to peek. Form your answer first; only then click Reveal.
Begin here. Single statements, single loops, simple nesting — the alphabet of analysis.
int sum(int a, int b) { int result = a + b; return result; }
int total(int arr[], int n) { int sum = 0; for (int i = 0; i < n; i++) { sum += arr[i]; } return sum; }
void printPairs(int n) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { printf("(%d,%d) ", i, j); } } }
void process(int arr[], int n) { for (int i = 0; i < n; i++) { arr[i] *= 2; } for (int i = 0; i < n; i++) { arr[i] += 1; } for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } }
Logarithms, triangles, and cubes. The same loop wears many faces, depending on how its index moves.
void doubler(int n) { for (int i = 1; i < n; i = i * 2) { printf("%d ", i); } }
void upperTriangle(int n) { for (int i = 0; i < n; i++) { for (int j = i; j < n; j++) { printf("*"); } printf("\n"); } }
void tripleLoop(int n) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { for (int k = 0; k < n; k++) { printf("."); } } } }
void mystery(int n) { int i = 1; while (i * i <= n) { printf("%d ", i); i++; } }
Now the loops cohabit. An outer linear march paired with an inner logarithmic stride; conditions that bend the bound. Think carefully about what dominates.
void analyze(int n) { for (int i = 0; i < n; i++) { for (int j = 1; j < n; j = j * 2) { printf("%d %d\n", i, j); } } }
void twoLoops(int n) { // First: nested quadratic for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { printf("."); } } // Then: a single linear sweep for (int k = 0; k < n; k++) { printf("!"); } }
void harmonic(int n) { for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j = j + i) { printf("*"); } } }
void conditional(int n) { for (int i = 0; i < n; i++) { if (i % 2 == 0) { for (int j = 0; j < n; j++) { printf("."); } } else { printf("!"); } } }
Here the function calls itself, and the analysis becomes a recurrence. Write down T(n), then solve.
int factorial(int n) { if (n <= 1) return 1; return n * factorial(n - 1); }
int binarySearch(int arr[], int lo, int hi, int key) { if (lo > hi) return -1; int mid = (lo + hi) / 2; if (arr[mid] == key) return mid; if (arr[mid] < key) return binarySearch(arr, mid + 1, hi, key); else return binarySearch(arr, lo, mid - 1, key); }
int fib(int n) { if (n <= 1) return n; return fib(n - 1) + fib(n - 2); }
void mergeSort(int arr[], int lo, int hi) { if (lo >= hi) return; int mid = (lo + hi) / 2; mergeSort(arr, lo, mid); // T(n/2) mergeSort(arr, mid + 1, hi); // T(n/2) merge(arr, lo, mid, hi); // O(n) }
void hanoi(int n, char from, char via, char to) { if (n == 0) return; hanoi(n - 1, from, to, via); printf("Move disk %d: %c -> %c\n", n, from, to); hanoi(n - 1, via, from, to); }