How to Practice DSA Problems: A Step-by-Step Routine for Data Structures and Algorithms
Updated
To improve at DSA problems, work in a fixed loop: pick one topic and difficulty band, write the approach and complexity before coding, implement and test, then log every failure in an error notebook and revisit it on a schedule. This routine fits anyone who already knows one programming language and basic syntax; if you are still learning loops and functions, finish that first, because DSA practice assumes you can already express an idea in code.
TutorialsPoint's practice section is one place to run this loop: it lists 3500+ coding problems and tutorials, sorted by difficulty, with solutions. The steps below are platform-agnostic — they work whether you use that set or another.
Step 1: Build a topic order, not a random problem feed
Random selection feels productive and teaches little, because each problem uses a different mental model. Group your practice by data structure and algorithm family, and finish one family before moving on.
A workable order:
- Arrays and strings (indexing, two pointers, sliding window)
- Hashing (frequency maps, sets, prefix sums)
- Linked lists (traversal, reversal, fast/slow pointers)
- Stacks and queues (monotonic stack, BFS queue)
- Trees (recursion, DFS, BFS, BST properties)
- Heaps and priority queues (top-k, merging)
- Graphs (representation, BFS/DFS, topological sort)
- Dynamic programming (1D, then 2D, then knapsack-style)
- Greedy and intervals
- Backtracking and recursion patterns
Within each topic, split by difficulty: easy problems to confirm the pattern, medium problems to force combination of ideas, hard problems only after mediums in that topic feel routine.
Step 2: Write the approach and complexity before you write code
For each problem, produce three things on paper or in a comment block before touching the editor:
- Input, output, and constraints — restated in your own words.
- Brute-force approach — the obvious solution, with its time and space complexity.
- Target approach — the pattern you think applies, and why.
Example: "Find two numbers in a sorted array that sum to a target."
- Brute force: check every pair, O(n²) time, O(1) space.
- Target: two pointers from both ends, O(n) time, O(1) space, valid because the array is sorted.
If you cannot state the target approach, that is the real signal — you are missing a pattern, not a line of code. Go read the pattern (for instance, how two pointers behave on sorted input), then return to the problem.
Step 3: Code, then test against the cases you predicted
Implement the target approach, then verify in this order:
- The sample cases from the problem.
- Edge cases: empty input, single element, all duplicates, maximum size, negative values, already-sorted or reverse-sorted input.
- A brute-force comparison on small random inputs, if the problem allows it.
Expected result: your solution passes samples and edges without you editing the logic mid-test. If it fails, note which case broke it — that detail goes straight into your error notebook.
Step 4: Keep an error notebook with failure causes, not just wrong answers
A list of problem names you failed is useless. Record the cause. Most failures fall into a small set of categories:
| Failure cause | What it looks like | Fix to practice |
|---|---|---|
| Wrong data structure | Using a list where a hash map gives O(1) lookup | Re-derive the complexity of each candidate structure |
| Missed edge case | Empty array, single node, overflow | Write edge cases before coding |
| Complexity too high | O(n²) accepted when O(n log n) was expected | Estimate constraints first: n = 10⁵ usually rules out O(n²) |
| Wrong pattern | Applying sliding window to a non-contiguous problem | Re-read the pattern's precondition |
| Off-by-one | Loop bounds, pointer movement | Trace the first and last iteration by hand |
Review the notebook weekly. Re-solve the problems you logged, from scratch, without looking at your old code.
Step 5: Move from brute force to optimal deliberately
Optimization is a skill you practice, not a talent. After a working brute-force solution, ask these questions in order:
- Can I trade space for time with a hash map or set?
- Is the input sorted, or can I sort it? (enables two pointers, binary search)
- Is the problem asking about contiguous ranges? (sliding window)
- Is it a shortest-path or level-order question? (BFS)
- Can I reuse overlapping subproblem results? (dynamic programming / memoization)
Common patterns worth naming explicitly, because recognizing them is most of the work: two pointers, sliding window, prefix sums, fast/slow pointers, monotonic stack, BFS/DFS, binary search on the answer, and 1D/2D DP.
Step 6: Set a weekly volume and a review rhythm
A routine you can sustain beats a burst you abandon. A concrete starting schedule:
- New problems: 3–5 per week in your current topic, mixed easy and medium.
- Review: 2 problems per week re-solved from your error notebook, no notes.
- Timing: give yourself 25–40 minutes on a medium before reading a hint; after a hint, finish the solution yourself.
- Topic switch: move on when you can solve mediums in that topic without hints, not when you have "done enough" problems.
Track two numbers only: problems solved without hints, and problems re-solved successfully after failing. Those two move together with actual skill; raw problem count does not.
Common places people get stuck
- Reading solutions too early. You learn the solution, not the pattern. Set a timer and honor it.
- Skipping the complexity estimate. Constraints in the problem statement usually tell you the intended complexity; ignoring them leads to accepted-but-slow habits.
- Practicing only easy problems. Easy problems confirm patterns; mediums build them. Spend most of your time on mediums in your current topic.
- Never revisiting failures. Re-solving logged problems is where retention comes from.
- Jumping topics weekly. Finish a family before starting the next, or the patterns blur together.
If you want a ready-made problem set to run this loop against, TutorialsPoint's practice problems are organized by difficulty and come with solutions, which suits the "attempt first, then compare" approach above.