Data Structures and Algorithms for Placements: A Beginner-Friendly Roadmap
By FreePare Team · Fri Jul 17 2026 · 12 min read
If you open a practice site for the first time and see a problem tagged "Dynamic Programming", it is easy to feel like you have walked into a room where everybody already knows the secret handshake. They do not. They started earlier and followed a path most beginners skip.
Most students do not fail at DSA because they are not clever enough. They fail because they try to learn everything at once with no map. One day it is arrays, the next it is tries, and by Friday they are watching a video on segment trees without knowing why an unbalanced binary search tree misbehaves.
This is that map — six phases over twelve weeks. What makes it usable rather than another topic list is that every phase ends with one problem you have to be able to solve, and the solution is here. If you can produce the code for a phase's exit test without looking, that phase is done. If you cannot, more problems from the next phase will not help.
Why this is what companies test
Not because they want to see whether you memorised quicksort. Data structures and algorithms are the closest thing software has to a universal problem-solving language. When you understand how a hash map works you stop writing nested loops to find duplicates. When you understand recursion you stop fearing tree problems. When you understand time complexity you stop writing code that times out on large inputs.
DSA is the toolkit, not the destination. The order below is the order in which the tools stop being confusing.
Phase 1, weeks 1 and 2: arrays, strings and complexity
Stay here until you are comfortable — and not "I can loop through an array" comfortable. The bar is solving a problem in one pass without allocating a second array.
Cover traversal and shifting, the two-pointer technique with pointers from both ends and with a slow and a fast pointer, sliding windows of fixed and variable size, and basic string manipulation. Alongside it, learn to recognise O(1), O(log n), O(n), O(n log n) and O(n²), and to know that a nested loop over 100,000 items is already too slow.
Exit test: remove duplicates from a sorted array, in place
Given a sorted array, move the unique values to the front and return how many there are. No second array.
def remove_duplicates(nums):
if not nums:
return 0
write = 1
for read in range(1, len(nums)):
if nums[read] != nums[write - 1]:
nums[write] = nums[read]
write += 1
return write
Two pointers, and they move at different speeds — read visits every position, write only advances when something new is kept. Trace it on [1, 1, 2, 2, 3]:
- read = 1: nums[1] is 1, the last kept value is 1, so skip.
- read = 2: nums[2] is 2, last kept is 1, so write it at position 1. Array is now [1, 2, 2, 2, 3], write = 2.
- read = 3: nums[3] is 2, last kept is 2, so skip.
- read = 4: nums[4] is 3, last kept is 2, so write it at position 2. Array is [1, 2, 3, 2, 3], write = 3.
Return 3, and the first three positions hold [1, 2, 3]. The tail is left as rubbish on purpose — that is what "in place" costs, and interviewers expect you to say so.
The mistake beginners actually make is building a new list and returning it. It passes the test case and fails the question, because the question was about the one thing you were asked not to do. Check your own solution by asking what it allocates.
Phase goal: 15 to 20 easy array and string problems, stating the time and space complexity of each before you look at any solution.
Phase 2, weeks 3 and 4: linked lists, stacks and queues
Now move to structures that connect nodes instead of sitting in one contiguous block. Singly linked lists first, then doubly. Then stacks, where the most recent element is the one that matters — valid parentheses, next greater element, evaluating a postfix expression. Then queues, including circular and priority queues, because the last of those leads straight into heaps.
Exit test: reverse a linked list
def reverse(head):
prev = None
node = head
while node:
nxt = node.next
node.next = prev
prev = node
node = nxt
return prev
Trace it on 1 to 2 to 3. Before the loop, prev is nothing and node is 1.
- Save nxt = 2. Point 1 backwards at nothing. prev = 1, node = 2. The list is now 1, and 2 to 3 held separately.
- Save nxt = 3. Point 2 backwards at 1. prev = 2, node = 3.
- Save nxt = nothing. Point 3 backwards at 2. prev = 3, node = nothing, so the loop ends.
Return prev, which is 3, and the list reads 3, 2, 1.
The mistake beginners actually make is dropping the first line. Write node.next = prev before saving nxt and the rest of the list becomes unreachable — and worse, the following node = node.next now assigns node to itself, so the loop never ends and the program hangs. That single saved reference is the whole trick, and it is why this problem is asked so often.
Phase goal: 10 to 15 problems. Do not move on until you can implement a stack and a queue from scratch.
Phase 3, weeks 5 and 6: trees and heaps
This is where beginners panic, because trees are recursive and recursion feels abstract. The way through is narrower than it looks: if you understand how a function calls itself and returns, most tree problems become ordinary.
Cover the traversals — inorder, preorder, postorder, both recursively and iteratively, plus level order using a queue. Then height, diameter, checking balance, and lowest common ancestor. Then binary search trees, whose whole power is one property: everything in the left subtree is smaller than the node and everything in the right is larger. Then heaps, which are complete binary trees with an ordering rule, and heapify, which is why the operations are O(log n).
Exit test: the height of a binary tree
def height(node):
if node is None:
return 0
return 1 + max(height(node.left), height(node.right))
Four lines, and if you can explain why they work you have understood recursion. The base case says an absent tree has height 0. Every other case says: whatever the taller side is, this node adds one to it.
Trace a tree whose root has a left child with no children, and a right child that itself has one child. Height of the leaf is 1 + max(0, 0) = 1. Height of the right child is 1 + max(1, 0) = 2. Height of the root is 1 + max(1, 2) = 3.
The mistake beginners actually make is returning 0 for a leaf instead of 1, by testing whether both children are absent rather than testing whether the node itself is. That version then crashes on an empty tree, which is the first thing an interviewer will hand you.
Phase goal: 15 to 20 tree problems. If recursion still feels unnatural, stay here. Everything after this phase is built on it.
Phase 4, weeks 7 and 8: graphs
Graphs look intimidating because they are not linear, but placement interviews rarely go deep. They test whether you can traverse one.
Learn adjacency lists and adjacency matrices — lists are what you want in an interview. Then breadth-first search, which uses a queue, and depth-first search, which uses recursion or a stack. Those two solve the majority of graph questions asked in campus placements. After that, shortest paths — Dijkstra for weighted graphs with non-negative edges, and the fact that plain BFS already gives the shortest path when every edge costs the same — and cycle detection in both undirected and directed graphs.
Exit test: shortest path in an unweighted graph
from collections import deque
def shortest_path(graph, start, target):
seen = {start}
queue = deque([(start, 0)])
while queue:
node, distance = queue.popleft()
if node == target:
return distance
for neighbour in graph[node]:
if neighbour not in seen:
seen.add(neighbour)
queue.append((neighbour, distance + 1))
return -1
BFS visits everything one step away, then everything two steps away, and so on — so the first time it reaches the target, it has arrived by the shortest route. That is the entire reason BFS answers this and DFS does not.
The mistake beginners actually make is marking a node as seen when it comes off the queue instead of when it goes on. The same node then gets queued several times before it is processed, and on a dense graph the queue grows enormous. Mark on the way in.
Phase goal: 10 to 12 problems, mostly BFS and DFS variations. Leave Floyd-Warshall and Bellman-Ford alone unless you have spare time.
Phase 5, weeks 9 to 11: algorithms and dynamic programming
You have the structures. Now the thinking that uses them.
For sorting, do not memorise ten algorithms. Know merge sort as divide-and-conquer, stable, always O(n log n); know quick sort as in-place, O(n log n) on average and O(n²) at worst; and know bubble and insertion sort as things to understand rather than use. For searching, binary search — and not only on arrays, because binary search on an answer range is a very common interview move. Then recursion and backtracking, which is recursion with a choice and an undo: subsets, N-Queens, permutations.
Exit test: climbing stairs, all three ways
You can climb one or two steps at a time. How many ways are there to climb n steps? Start with the honest brute force:
def ways(n):
if n <= 2:
return n
return ways(n - 1) + ways(n - 2)
It is correct — ways(5) is 8 — and it is unusable. Count the calls and you find 109 of them for n = 10 and 1,664,079 for n = 30, because ways(28) is computed over and over by different branches. That number is the whole motivation for dynamic programming, and it is worth counting yourself rather than taking on trust.
The fix is not a new idea, it is remembering answers you already computed. Once you have added a cache, notice that each answer only ever needs the previous two, so the table collapses to two variables:
def ways(n):
if n <= 2:
return n
a, b = 1, 2
for _ in range(3, n + 1):
a, b = b, a + b
return b
Same answers, O(n) time and O(1) space. Check the two against each other for n from 1 to 10 before you trust either — they should read 1, 2, 3, 5, 8, 13, 21, 34, 55, 89.
The mistake beginners actually make is jumping straight to the loop because they recognised the pattern. Then a problem arrives that is not Fibonacci in disguise and there is nothing to fall back on. Always write the recursion first, even when you can see the answer; the recursion is what tells you what to cache.
Master these five and the rest of DP starts making sense: climbing stairs, house robber, 0/1 knapsack, longest common subsequence, and coin change.
Phase goal: 20 to 25 problems across algorithms and DP.
Phase 6, week 12: revision and mocks
The last week is not for new topics. Solve on a timer, 20 to 30 minutes a problem. Explain your solution out loud while you write it. Write code in a plain text editor with no autocomplete, because that is the interview. And re-solve the problems you got wrong in earlier weeks rather than picking new ones.
How to practise without burning out
One platform is enough. Platform hopping is procrastination with a progress bar.
Do not read the solution early. Give a problem 20 to 30 minutes before you look at a hint. Reading solutions trains recognition, and recognition is not what the interview asks for.
Keep a problem journal. For each problem: the approach, why it worked, the time and space complexity, and what you would do differently. That journal is your revision material in week 12, and it is far more useful than re-reading the problems.
Consistency beats intensity. Two problems a day for three months beats fifty in a weekend followed by three weeks of nothing.
Common mistakes
- Starting with hard problems. If easy array problems are still a struggle, a hard DP question only tells you what you already know.
- Ignoring the why. Knowing that merge sort is O(n log n) is worth very little; knowing that it is because the array halves log n times and each level does n work is what you can actually use.
- Neglecting edge cases. Empty input, one element, all duplicates, negative numbers, the maximum constraint. Every exit test above breaks on at least one of these if written carelessly.
- Memorising instead of understanding. If you can solve two-sum but not three-sum, you memorised.
- Not timing yourself. An interview gives you 30 to 45 minutes. Two hours on a medium problem is information about your preparation, not about the problem.
The timeline

Twelve weeks in total. With less time, compress phases 4 and 5. Do not compress 1 and 2 — everything else stands on them, and the exit tests are how you find out whether they actually hold.
Start with one exit test
Do not start by planning twelve weeks. Open an editor and write remove_duplicates from memory, then run it on an empty list, on a single element, and on [1, 1, 1].
If it works, phase 1 is real for you and you can move on. If it does not, you have found out in four minutes where to begin — which is the only thing a roadmap is actually for.
Tags: campus-placement, freshers-placement-guide, dsa-guide