To understand an algorithm, don’t start from its code. Start from the problem it solves, try the obvious slow solution yourself, find where that solution wastes work, and only then look at how the algorithm removes the waste. Then rewrite it from memory a few days later. That loop, repeated over a short list of techniques, works better than reading many solutions.
Learn the prerequisites first
Most “I can’t understand this algorithm” problems are really missing basics. Before graphs and dynamic programming, you need:
- Arrays, strings, hash maps and sets. You should know what lookup, insert and delete cost for each.
- Loops, recursion and the call stack. If you cannot trace a recursive function by hand, trees and backtracking will not make sense.
- Big O notation. You need enough to say why a nested loop is O(n²) and why halving the input each step gives O(log n). The linear time complexity lesson is a good start.
A study loop for any single algorithm
Use the same steps each time. They take about an hour per algorithm at first, and less as the patterns repeat.
- State the problem in one sentence, with inputs, outputs and constraints. “Given a sorted array and a target, return the target’s index or -1.” If you can’t, you are not ready to read the solution.
- Solve it the slow way. Brute force is a legitimate first answer, and writing it shows you what the clever version improves.
- Find the waste. Where does the brute force repeat work or ignore information? That is the idea you are trying to learn.
- Read or watch the real algorithm, then trace it by hand on a small input, writing down the variables at each step.
- Close the source and implement it yourself. Run it on edge cases: empty input, one element, duplicates, the target missing.
- Write down the time and space cost, and why. One or two sentences in your own words.
- Revisit after two or three days, then after a week. Implement it again without looking. Forgetting something is information: it shows what you have not understood yet.
Example: from brute force to hash map
Take Two Sum: find two numbers in a list that add up to a target. The brute force checks every pair:
def two_sum_brute(nums, target):
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
if nums[i] + nums[j] == target:
return [i, j]
return []
The waste: for each number x, you scan the rest of the list looking for target - x. A hash map answers “have I seen that value?” in constant time on average, so you can remember numbers as you go:
def two_sum_hash(nums, target):
seen = {} # value -> index
for i, x in enumerate(nums):
if target - x in seen:
return [seen[target - x], i]
seen[x] = i
return []
print(two_sum_brute([2, 7, 11, 15], 9)) # [0, 1]
print(two_sum_hash([2, 7, 11, 15], 9)) # [0, 1]
Both print [0, 1]. The brute force is O(n²) time and O(1) extra space; the hash map version is O(n) time and O(n) space. You traded memory for speed, and you can say exactly where the saving comes from. That understanding is what transfers to the next problem. You can practice this one step by step in the AlgoCademy lessons Two Sum (brute force).
Example: tracing by hand
Tracing is the step people skip. Here is binary search with a print statement added, so you see the state at each step:
def binary_search(a, target):
lo, hi = 0, len(a) - 1
while lo <= hi:
mid = (lo + hi) // 2
print(f"lo={lo} hi={hi} mid={mid} a[mid]={a[mid]}")
if a[mid] == target:
return mid
if a[mid] < target:
lo = mid + 1
else:
hi = mid - 1
return -1
print(binary_search([1, 3, 5, 7, 9, 11, 13], 11))
Output:
lo=0 hi=6 mid=3 a[mid]=7
lo=4 hi=6 mid=5 a[mid]=11
5
Seven elements, two looks. Each comparison throws away half of the remaining range, which is where O(log n) comes from. Do the trace on paper first, then compare with the printed output. The Binary Search lesson lets you do the same with feedback. Doing this trace aloud is also what interviewers expect when you dry-run your code.
Study by pattern, not by problem
There are thousands of problems and a few dozen reusable ideas. After you have done a handful of problems with the same idea, name it. A reasonable order:
- Hash maps and sets for lookup and counting
- Two pointers and sliding window (arrays and strings)
- Binary search, including searching on an answer
- Sorting and what it enables
- Stacks and queues
- Recursion, then trees and depth-first search
- Breadth-first search and graphs
- Backtracking
- Greedy choices
- Dynamic programming, starting from a recursive solution and adding memoization
Our post on algorithm design patterns covers some of these in more detail.
A weekly plan you can keep
Five or six hours a week, spread over several days, beats one long weekend session, because spacing is what makes recall stick. One possible week:
- Two sessions of 60 to 90 minutes: one new pattern, using the study loop on two or three problems.
- One session of 45 minutes: redo problems from the previous one to two weeks, from a blank file.
- One short session: read your notes on the pattern and write its template in a few lines, for example “sliding window: grow right, shrink left while invalid”.
Keep a notebook or file with one entry per problem: the idea in one line, the cost, and the mistake you made. Reread the mistakes before sessions. Most people repeat the same two or three errors (off-by-one in binary search, forgetting to handle empty input, mutating a list while looping over it).
Use visual tools, but draw too
Animations of sorting and graph traversal help you see the shape of the process. They are most useful after you have tried the algorithm on paper, as a check. If you only watch, it is easy to feel you understand when you don’t. Many free visualizers exist for sorting, trees and graphs.
Choosing sources
One good source per topic is enough; switching between six explanations of the same idea is a common way to avoid doing the exercises.
- A textbook such as Introduction to Algorithms (CLRS, fourth edition 2022) when you want proofs and exact analysis. It is dense for a first pass.
- Video courses and lectures for intuition; many universities publish algorithm courses free online.
- An interactive course when you want to write code from the start and get feedback. AlgoCademy is one; LeetCode, HackerRank and Codeforces are practice sites with large problem sets but less teaching, so they work better once you know the basics.
- AI assistants are useful for asking “why does this line work?” or for hints. If you ask for the full solution first, you skip the struggle that makes the learning stick, so ask for a hint or a counterexample instead.
Common mistakes
- Memorizing code. You can reproduce it for a week, then lose it. If you can’t explain why each line exists, you have memorized it.
- Reading solutions too soon. Struggle for 20 to 30 minutes on a problem before looking for help, and when you do look, take a hint and not the whole answer if you can.
- Skipping complexity analysis. Interviewers ask for it, and it is how you choose between two correct solutions.
- Only doing problems of one type. Mix patterns once you know a few, so you learn to recognise which one applies.
- Not re-solving. Solving a problem once proves little. Solving it again after a week proves you understood it.
- Studying proofs before you need them. They matter if you want a deep theory background. For most programmers, a clear argument for why the algorithm is correct (an invariant, or why each step is safe) is enough.
Checking your understanding
For any algorithm, you should be able to do these without notes: explain it to someone in two minutes, write it from scratch, state its time and space cost, give a case where it fails or is slow, and name a problem where a different algorithm is better. If you can’t answer one of them, that is the part to study next.