Step-by-step procedure to solve a problem. Input, process, output.
Self-serve tutorial - low prerequisites, straightforward concepts.
Every program you’ve ever run—sorting photos, searching a contact, recommending a video—depends on an algorithm: a clear procedure that turns inputs into outputs.
An algorithm is a step-by-step procedure for solving a problem: it takes input, performs a process (ordered steps), and produces output. Good algorithms are precise, finite (they terminate), and correct (they produce the right output for every valid input).
When people first learn programming, it can feel like the computer “just does things.” But computers don’t understand goals like “find the best route” or “put these numbers in order.” They only follow instructions.
An algorithm is the bridge between a human goal and mechanical execution.
Learning what an algorithm is gives you a vocabulary for everything that comes later: correctness, efficiency, data structures, and eventually Big O notation.
An algorithm is a finite, ordered sequence of unambiguous steps that transforms input into output.
We can summarize it as a mapping:
input → process → output
Using the key symbol:
input → output (via a well-defined procedure)
Algorithms are often compared to recipes. That’s helpful, but algorithms are stricter than most recipes:
This node is built from three atomic ideas:
It helps to separate “algorithm” from nearby ideas:
| Term | What it is | How it relates to algorithms |
|---|---|---|
| Problem | A goal, stated in words | Algorithms solve problems |
| Program | Code written in a programming language | A program can implement an algorithm |
| Function | A reusable piece of code | Often implements an algorithm for a specific task |
| Heuristic | A rule of thumb that often works | Not guaranteed to be correct for all inputs |
A single algorithm can be implemented by many different programs (Python, Java, C++). And one program might contain multiple algorithms.
Most of the time in computer science, when we say “algorithm,” we expect these properties:
You don’t need to prove all of these formally yet—but you should know what you’re aiming for.
If you can reliably identify input, process, and output, you can:
This is the backbone of algorithmic thinking.
Input is any information the algorithm uses to do its job.
Examples:
Sometimes input is empty (an algorithm might generate something, like the first 100 primes). Even then, you can think of the input as “the number 100” or “a stopping rule.”
Output is the result you promise to deliver.
Examples:
A good habit: define output as a contract.
If the input satisfies X, the algorithm will output Y.
This mindset will later help you reason about correctness.
The process is the ordered list of operations that turns input into output.
At a beginner level, most algorithm steps come from a small toolkit:
Problem: Given a non-empty list of numbers, return the largest number.
You can describe it in plain steps:
That is already an algorithm.
An algorithm is not just “a set of steps,” it’s an ordered sequence.
Consider these two instructions:
The order affects what happens. In computing, order is even stricter: doing something before a variable is initialized might crash a program or produce nonsense.
Many beginner algorithms are deterministic:
Some algorithms use randomness (later you may see randomized algorithms), where:
At this node, focus on deterministic algorithms; the input → output mapping is the cleanest.
You can think of an algorithm like a function f that maps inputs to outputs:
f(input) → output
For example, if input is a number n and output is n²:
f(n) = n²
But be careful: not every algorithm is “just a formula.” Many algorithms define f through a sequence of steps (like scanning a list) rather than a closed-form expression.
You’ll see → used to mean “maps to” or “transforms into.”
Example: if we keep a variable best, one step might be:
(best, x) → (max(best, x))
You don’t need to write it this way all the time, but it captures the idea that each step transforms the current state into a new state.
Many “almost algorithms” fail because they are:
Learning to check these early saves a lot of time later.
An algorithm must be clear enough that two different people (or computers) do the same thing.
Ambiguous instruction:
Precise instruction:
Even more precise (when needed):
Notice how precision often means defining edge cases.
An algorithm should finish in a finite number of steps.
A loop like:
is not an algorithm for a typical problem (unless the output is meant to be an ongoing stream).
A common way to ensure termination is to have a loop that makes measurable progress:
If i starts at 1 and you do i ← i + 1 until i = n, you will stop after n − 1 increments.
Correctness means: for every valid input, the output matches the problem’s definition.
At this stage, you can reason informally by asking:
An invariant is a statement that stays true as your algorithm runs.
For the maximum-finding algorithm, an invariant could be:
Why that helps:
You don’t need formal proof syntax yet. But this style of reasoning—maintaining a true statement while progressing—will become extremely powerful.
If you test only a few inputs, you might miss failures.
Example: an incorrect algorithm for maximum might start with best ← 0. It works for lists of positive numbers but fails for lists like [-5, -2].
Correctness requires thinking beyond a few examples.
Later you’ll see algorithms that operate on vectors like v ∈ ℝⁿ. For instance, an algorithm might take v as input and output ‖v‖ (its length).
Even though this node is foundational, the same input → process → output framing applies:
You don’t need vector math to understand what an algorithm is, but it shows that algorithms generalize far beyond lists of integers.
Once you can clearly describe an algorithm, the next natural question is:
How efficient is it?
Two algorithms can solve the same problem but take very different amounts of time as input size grows. Big O notation is the standard language for talking about that growth.
This node “unlocks” Big O because Big O is about algorithms specifically—their step counts, memory usage, and scaling behavior.
Consider the maximum-finding algorithm on a list of length n.
So the work grows roughly proportionally to n.
That idea becomes:
Another example: checking if two lists are identical element-by-element also takes work proportional to n in the worst case.
Suppose you want to find whether a number x is in a list of n numbers.
Approach A: scan from the beginning until you find x.
Approach B (if the list is sorted): use binary search.
At this node, you don’t need to master these algorithms yet; the key point is:
To understand Big O well, you need the habits from this lesson:
Once you can do that, you can translate “steps” into growth rates.
Algorithms aren’t only for “classic CS problems.” They appear in:
In all cases, the structure remains:
input → process → output
That’s why this node is foundational.
Problem: Given a list of numbers L = [ℓ₁, ℓ₂, …, ℓₙ], compute the sum S = ∑ᵢ ℓᵢ.
Input: list L of length n (possibly n = 0).
Output: number S (0 if the list is empty).
Define the goal precisely:
We want output S such that
S = ∑ᵢ ℓᵢ.
If n = 0, then S = 0.
Write a clear procedure:
1) Set total ← 0.
2) For each element x in L:
total ← total + x
3) Output total.
Trace it on a concrete input L = [3, 1, 4]:
Start: total = 0
Read 3: total = 0 + 3 = 3
Read 1: total = 3 + 1 = 4
Read 4: total = 4 + 4 = 8
Output: 8
Check termination:
The loop runs once per element.
If the list has n elements, there are exactly n iterations, so it stops.
Check correctness (informal invariant):
Invariant: after processing the first k elements, total = ∑_{i=1..k} ℓᵢ.
Insight: Many algorithms are “accumulators”: maintain a running value (total, best, count) that summarizes what you’ve seen so far. The key is choosing an invariant that explains why the accumulator is always correct.
Problem: Given a non-empty list L = [ℓ₁, ℓ₂, …, ℓₙ] with n ≥ 1, return max(L).
Input: non-empty list of numbers.
Output: the largest number in the list.
Be precise about input constraints:
The list must be non-empty (n ≥ 1) so that a maximum exists as one of the elements.
Procedure (step-by-step):
1) Set best ← ℓ₁.
2) For i = 2 to n:
If ℓᵢ > best, set best ← ℓᵢ.
3) Output best.
Trace it on L = [2, 9, 5, 9]:
Start: best = 2
Compare 9 > 2 → yes, best = 9
Compare 5 > 9 → no, best = 9
Compare 9 > 9 → no (not greater), best = 9
Output: 9
Termination:
The loop runs from i = 2 to n, which is (n − 1) iterations, so it must finish.
Correctness reasoning (invariant):
Invariant: after processing ℓ₁..ℓ_k, best = max(ℓ₁..ℓ_k).
Insight: A good algorithm often keeps a small summary of what matters (here: the best seen so far) instead of storing everything again. This is both conceptually clean and efficient.
Problem: Given a string s of length n, return True if it reads the same forward and backward, else False.
Input: string s (possibly empty).
Output: Boolean (True/False).
Clarify what it means:
A string s is a palindrome if
∀ i, s[i] = s[n − 1 − i]
for indices i in the first half of the string.
Procedure:
1) Let n be the length of s.
2) For i = 0 to ⌊(n − 1)/2⌋:
If s[i] ≠ s[n − 1 − i], output False.
3) Output True.
Trace on s = "racecar" (n = 7):
i=0: s[0]=r, s[6]=r → equal
i=1: s[1]=a, s[5]=a → equal
i=2: s[2]=c, s[4]=c → equal
i=3 is the middle; loop ends
Output True
Trace on s = "hello" (n = 5):
i=0: h vs o → not equal
Output False immediately
Termination:
The loop runs at most ⌊n/2⌋ iterations, so it always stops.
Correctness intuition:
The algorithm checks exactly the pairs of characters that must match. If any pair fails, the definition is violated, so False is correct. If all pairs match, the definition holds, so True is correct.
Insight: Many algorithms work by reducing the problem to a set of required checks. Here, the definition itself suggests the algorithm: compare symmetric pairs until you reach the middle.
An algorithm is a finite, ordered sequence of unambiguous steps that transforms input → output.
Algorithms are about procedures, not programming languages: the same algorithm can be implemented in many languages.
Always identify the algorithm “shape”: input, process (steps), output (contract).
Good algorithms are precise (no vague steps), terminate (finish), and are correct (work for all valid inputs).
Informal invariants (“what stays true after each step”) are a powerful way to reason about correctness.
Order matters: changing step order can change results or break the procedure.
This node prepares you for analyzing efficiency and scaling, which leads directly to Big O notation.
Confusing an algorithm with a program: code is one implementation; the algorithm is the underlying procedure.
Leaving steps ambiguous (e.g., “repeat until done”) without defining what “done” means or how to detect it.
Forgetting edge cases (empty list, negative numbers, duplicates), leading to algorithms that work only sometimes.
Writing loops that don’t make progress toward stopping, risking non-termination.
Write an algorithm (plain English steps) that counts how many even numbers are in a list L of integers.
Hint: Use an accumulator variable that starts at 0, and increase it when you see an even number (x mod 2 = 0).
Input: list L.
Output: count of elements x ∈ L such that x is even.
Algorithm:
1) Set count ← 0.
2) For each element x in L:
If x mod 2 = 0, set count ← count + 1.
3) Output count.
Termination: the loop runs once per element.
Correctness idea: after processing k elements, count equals the number of even elements among the first k elements.
Design an algorithm that returns True if a list L contains the number 0, otherwise returns False.
Hint: Scan the list and stop early if you find 0.
Input: list L of numbers.
Output: Boolean.
Algorithm:
1) For each element x in L:
If x = 0, output True.
2) After the loop ends, output False.
Termination: finite list → loop ends.
Correctness: if 0 appears, the algorithm finds it and returns True; if it never appears, returning False matches the definition.
A student proposes this algorithm to find the maximum: “Set best ← 0. For each x in L, if x > best then best ← x. Output best.” Give a counterexample input where it fails, and fix the algorithm.
Hint: Think about lists with all negative numbers. The fix is usually to initialize best using the first element of the list (assuming non-empty).
Counterexample: L = [−5, −2].
Student algorithm:
best = 0
Check −5 > 0? no
Check −2 > 0? no
Outputs 0, but 0 is not in the list and max(L) = −2.
Fix (for non-empty L):
1) Set best ← first element of L.
2) For each remaining element x in L:
If x > best, best ← x.
3) Output best.
This works for negative numbers because best starts as an actual element of L.
Next node: Big O Notation
Related future ideas you’ll meet soon:
This node is the foundation: Big O, data structures, and algorithm design all assume you can clearly state input → process → output.