DSA

Data Structures and Algorithms Interview Guide

This page is a complete roadmap for the coding interview, from Big-O notation to dynamic programming. It explains every data structure and every problem-solving pattern that interviews rely on, gives you a step-by-step method for solving a problem you have never seen, and shows how to tell from the input size which complexity you need. Each topic ends with a practice task, linked to a problem on this site where one is available.

It suits students preparing for placements and internships, engineers returning to interviews after years in a job, and anyone who has solved problems at random and wants a structure. Work through the stages in order and tick off topics as you go; your progress stays in this browser. The second half of the page lists the practice problems by pattern, gives a twelve-week plan, and answers the questions candidates ask most.

Level
Beginner to interview-ready
Time
10–16 weeks at about 10 hours a week; 4–6 weeks to refresh if you have done this before
Scope
45 topics in 10 stages, with practice problems for each pattern
Before you start
Basic programming in one language: variables, loops, functions, lists and dictionaries

What you will be able to do

  • Analyse the time and space complexity of any solution, and work out the complexity a problem needs from its input size
  • Choose the right data structure for a task and know the cost of every operation on it
  • Recognise the twenty or so patterns behind most interview problems from clues in the statement
  • Solve medium problems in about 30 minutes with clean, tested code, explaining your reasoning as you go
  • Write recursion, backtracking and dynamic programming solutions methodically instead of by guesswork
  • Handle the interview itself: clarifying, communicating, testing and responding to hints

What the coding round tests

In a coding interview you get one or two problems and about 45 minutes. The interviewer is not only checking whether you reach the answer. They score four things: problem solving (do you find a correct, efficient approach and reason about it), coding (is the code correct, readable and idiomatic), verification (do you test it and find your own bugs) and communication (can they follow your thinking and does a hint help you). A candidate who explains a near-optimal solution clearly and tests it well often scores higher than one who silently writes the optimal one.

Interviews reuse a limited set of ideas. Learning the data structures well and recognising the patterns lets you reduce most new problems to something you have seen, which is why this page is organised by pattern rather than by company.

What is expected at each level

Internships and graduates

  • Easy and medium problems on arrays, strings, hash maps, linked lists, trees and basic graphs
  • A correct solution with the right complexity, even if it takes a hint to get there
  • Clear code and a walk through test cases at the end

Mid level

  • Medium problems solved optimally in 25 to 35 minutes, sometimes two per round
  • Confident with heaps, graphs, binary search on the answer and common dynamic programming
  • Handles follow-ups such as streaming input or tighter memory limits

Senior and above

  • The same coding bar, still expected to be fast and clean, often with harder follow-ups
  • Production-quality code: clear structure, error handling, sensible names
  • Explains trade-offs between approaches, not only the final answer

How to solve any problem: the six-step method

Use these steps on every problem, in practice and in the interview. They stop you from coding the wrong thing and give the interviewer something to score even if you do not finish.

  1. Understand the problem2–3 min

    What to do. Restate the problem in your own words. Ask about input size, value ranges, duplicates, negative numbers, empty input, whether the input is sorted and what to return when there is no answer.

    Why it matters. The constraints tell you the target complexity, and edge cases you agree now are the tests you run later.

  2. Work through examples2–3 min

    What to do. Take the given example, then make one small one and one tricky one. Solve them by hand and watch what you do; your hands often find the algorithm before your head does.

    Why it matters. Examples expose misunderstandings before any code exists.

  3. State a brute-force solution2 min

    What to do. Describe the simplest correct approach, often trying every pair, subset or position, and state its complexity. Do not code it unless the interviewer asks.

    Why it matters. It proves you understand the problem and gives a baseline to improve on.

  4. Optimise5–10 min

    What to do. Find the repeated or wasted work in the brute force. Ask: would sorting help? Can a hash map remember what I have seen? Is there a window, a stack, a heap or a graph hiding here? Compare with the target complexity from the input size.

    Why it matters. Say the approach and its complexity out loud and get agreement before coding.

  5. Write the code10–15 min

    What to do. Code in small, named pieces. Use helper functions, clear variable names and the standard library. Talk while you write, but keep momentum.

    Why it matters. Clean code is easier to debug and is part of the score.

  6. Test and fix5 min

    What to do. Trace your code line by line on a small example, then check the edge cases you listed in step 1. Fix bugs calmly and say what you changed.

    Why it matters. Finding your own bugs scores far better than having the interviewer find them.

Complexity tables

From input size to target complexity

A typical judge or interviewer expects around 108 simple operations a second at most. Use the largest input size to work out which complexity will pass, then look for an approach with that complexity.

Largest nTarget complexityTypical approaches
up to 10–12O(n!) or O(2n · n)Try every ordering or subset with backtracking
up to 20–25O(2n)Subsets, bitmask dynamic programming, meet in the middle
up to 100–500O(n3)Three nested loops, interval dynamic programming, all-pairs shortest paths
up to 5,000O(n2)Pairs, two-dimensional dynamic programming
up to 105–106O(n log n) or O(n)Sorting, heaps, binary search, hash maps, two pointers, sliding windows, prefix sums
above 108O(log n) or O(1)Maths, binary search on the answer

Cost of common operations

StructureAccess or searchInsertDeleteNotes
Dynamic arrayO(1) by index, O(n) searchO(1) amortised at end, O(n) in middleO(n) in middleContiguous, cache friendly
Hash map or setO(1) averageO(1) averageO(1) averageNo order; O(n) worst case with many collisions
Linked listO(n)O(1) at a known nodeO(1) at a known nodeGood for splicing, poor for random access
Stack, queue, dequeO(1) at the endsO(1)O(1)Use a deque for both ends
Binary heapO(1) peek min or maxO(log n)O(log n) popBuilding from n items is O(n)
Balanced search treeO(log n)O(log n)O(log n)Keeps order: floor, ceiling, range queries
TrieO(L) for a word of length LO(L)O(L)Prefix queries
Union-findnearly O(1)nearly O(1) unionnot supportedWith path compression and union by rank

Which pattern fits?

Clues in the problem statement often point straight at a pattern. Use this table as a first guess, then check the guess against the input size.

If the problem says or impliesTry
Sorted array, find a pair or triple with a target sumTwo pointers
Longest or shortest contiguous subarray or substring with a propertySliding window
Sum of a range, or count subarrays with a given sumPrefix sums with a hash map
Have I seen this value, or count frequenciesHash map or set
Sorted input, or minimise the maximum or maximise the minimumBinary search, or binary search on the answer
Next greater or smaller element, or spansMonotonic stack
Matching brackets, undo, nested structureStack
Top k, k-th largest, merge k sorted lists, running medianHeap
Overlapping ranges, meetings, merging timesSort by start, then sweep
Shortest path in an unweighted grid or graph, minimum stepsBreadth-first search
Weighted shortest path with non-negative weightsDijkstra's algorithm
Dependencies or ordering constraintsTopological sort
Connected groups, merging sets, detecting a cycle as edges arriveUnion-find
All combinations, permutations or subsetsBacktracking
Count the ways, or the best value, with overlapping subproblemsDynamic programming
Prefix lookups over many wordsTrie
Linked list cycle or middle elementFast and slow pointers

The roadmap

Work through the stages in order; each builds on the ones before. Core topics appear in most interviews; recommended topics appear often; optional topics matter for harder loops and competitive programming.

  1. Stage 1FoundationsBeginner · 1–2 weeks · 4 topics
  2. Stage 2Arrays and stringsBeginner · 2 weeks · 6 topics
  3. Stage 3HashingBeginner · 1 week · 3 topics
  4. Stage 4Linked lists, stacks and queuesIntermediate · 1–2 weeks · 5 topics
  5. Stage 5Binary searchIntermediate · 1 week · 3 topics
  6. Stage 6Trees and triesIntermediate · 2 weeks · 5 topics
  7. Stage 7Heaps, intervals and greedyIntermediate · 1–2 weeks · 4 topics
  8. Stage 8GraphsAdvanced · 2 weeks · 5 topics
  9. Stage 9Backtracking and dynamic programmingAdvanced · 2–3 weeks · 5 topics
  10. Stage 10Advanced topics and data structure designAdvanced · 1–2 weeks · 5 topics

Stage 1 Foundations

Beginner1–2 weeks4 topics

Goal. Analyse any solution's cost, write recursion confidently and use your language's standard library.

Big-O notation and complexity analysis Core

Big-O describes how the work an algorithm does grows as the input grows, ignoring constant factors. O(1) is constant, O(log n) halves the problem each step, O(n) touches each item once, O(n log n) is typical of good sorting, O(n2) compares pairs, and O(2n) tries every subset. Analyse time and space, and usually the worst case.

To analyse code, count how often the innermost work runs: two nested loops over n is O(n2), a loop that halves its range is O(log n). Know amortised cost (appending to a dynamic array is O(1) on average even though an occasional resize is O(n)) and that recursion uses stack space proportional to its depth.

Practice. Write down the time and space complexity of five solutions you have already written, then check each with a colleague or by timing it on growing inputs.

Recursion Core

A recursive function solves a problem by calling itself on smaller inputs until it reaches a base case it can answer directly. Every recursive solution needs three things: the base case, a step that makes the problem smaller, and trust that the smaller call returns the right answer.

Analyse recursion with a recurrence or a recursion tree: a function that calls itself twice on n minus 1 does O(2n) work, while one that halves the input once per call does O(log n). Deep recursion can overflow the call stack, so know how to convert to an explicit stack, and know when to add memoisation because the same subproblem repeats.

Practice. Write recursive functions for power and for reversing a list, then solve Pow(x, n) and Reverse Linked List recursively.

Choosing a language and its standard library Core

Use the language you write most fluently. Python is concise and popular for interviews; Java and C++ are common and fast; JavaScript is fine, especially for front-end roles. What matters is knowing the standard library well enough not to reinvent it.

Learn, for your language: dynamic arrays and slicing, hash maps and sets, a double-ended queue, a heap or priority queue, sorting with a custom key, string building, and integer limits. In Python that means list, dict, set, collections.deque, Counter, defaultdict and heapq; in Java, ArrayList, HashMap, ArrayDeque and PriorityQueue.

Practice. Write a one-page cheat sheet of the ten library calls you use most in your chosen language, with their complexity.

Practising effectively Recommended

How you practise matters more than how much. Learn one pattern at a time: read the idea, solve three to five problems that use it, then mix it with earlier patterns. Struggle honestly for 20 to 30 minutes before looking at a hint, and only read the full solution after a second attempt.

Keep a log of every problem with the pattern, the key insight and your mistake. Revisit problems after one day, one week and one month; the practice workspace's review schedule does this for you. Explain solutions out loud, because that is what the interview asks for.

Practice. Pick three problems you solved a month ago and solve them again from scratch without notes.

Stage 2 Arrays and strings

Beginner2 weeks6 topics

Goal. Use arrays and strings fluently and apply two pointers, sliding windows and prefix sums.

Arrays and dynamic arrays Core

An array stores items in contiguous memory, so reading by index is O(1) and scanning is fast. Dynamic arrays grow by allocating a larger block and copying, which keeps appends O(1) amortised. Inserting or deleting in the middle shifts everything after it, costing O(n).

Common techniques: in-place updates to save memory, iterating from the end when you write into the same array, swapping to partition, and using the array's own indices as a hash when values are in the range 1 to n. Watch for off-by-one errors at the boundaries and for modifying a list while iterating over it.

Practice. Solve Move Zeroes in place, then First Missing Positive using the array itself as a hash.

Strings Core

Strings are arrays of characters, but in many languages they are immutable, so building a string by repeated concatenation can cost O(n2). Collect pieces in a list and join once, or use a string builder.

Know how to count characters with a fixed-size array or a hash map, compare strings by sorted characters or counts for anagram problems, reverse words, check palindromes from both ends, and parse numbers safely. Clarify the character set: lowercase letters only, ASCII, or full Unicode changes the data structure and the memory cost.

Practice. Solve Valid Palindrome and Backspace String Compare without building new strings.

Two pointers Core

Two pointers walk through a sequence together to avoid nested loops. In the opposite ends form, one starts at each end of a sorted array and they move inwards based on a comparison, as in finding a pair with a target sum in O(n). In the same direction form, a slow pointer marks where to write and a fast pointer reads, as in removing duplicates in place.

The pattern works because sorted order tells you which pointer to move: if the sum is too small, only moving the left pointer can increase it. Combine with sorting for three-sum style problems, giving O(n2) instead of O(n3).

Practice. Solve Squares of a Sorted Array with two pointers from the ends, then 3Sum and Container With Most Water.

Sliding window Core

A sliding window keeps a contiguous range and moves its ends instead of recomputing from scratch. Fixed-size windows add the new element and remove the old one each step. Variable-size windows grow the right end, and shrink the left end while the window breaks a rule, recording the best valid window.

left = 0
for right, x in enumerate(items):
    add(x)
    while window_invalid():
        remove(items[left]); left += 1
    best = max(best, right - left + 1)

Each element enters and leaves the window once, so the whole scan is O(n). Use a hash map for counts inside the window, or a monotonic deque when you need the window's maximum or minimum.

Practice. Solve Longest Substring Without Repeating Characters with a variable window, then Minimum Window Substring, then Sliding Window Maximum with a deque that keeps candidates in decreasing order.

Prefix sums Core

A prefix sum array stores the running total, so the sum of any range is a subtraction: prefix[j + 1] - prefix[i], in O(1) after O(n) setup. Two-dimensional prefix sums do the same for rectangles in a grid.

Combined with a hash map of earlier prefix values, prefix sums count subarrays with a given sum in O(n): at each position, look up how many earlier prefixes equal the current prefix minus the target. The same trick handles subarrays with equal numbers of two values, by treating one as plus one and the other as minus one.

Practice. Solve Subarray Sum Equals K with prefix sums and a hash map, and explain why a sliding window fails when values can be negative. Then solve Contiguous Array.

Sorting and its uses Core

Know the main algorithms: merge sort (O(n log n), stable, extra memory), quicksort (O(n log n) on average, in place, O(n2) worst case), heap sort, and counting or bucket sort for small integer ranges in O(n + k). Comparison sorts cannot beat O(n log n).

In interviews you rarely implement a sort, but you constantly sort as a first step: to use two pointers, to group equal items, to sweep intervals, or to make greedy choices. Learn custom comparators, and remember sorting costs O(n log n), which may already be the target complexity.

Practice. Solve Sort Colors in one pass, then Largest Number with a custom comparator, and explain why comparing a+b with b+a is the right rule.

Stage 3 Hashing

Beginner1 week3 topics

Goal. Use hash maps and sets to trade memory for speed in counting, lookup and grouping problems.

Hash maps and hash sets Core

A hash map stores key and value pairs and finds a key in O(1) on average, by computing a hash that points to a bucket. A hash set stores just keys. They are the single most useful tool in coding interviews: they turn many O(n2) searches into O(n).

Know their limits: no ordering, O(n) worst case when many keys collide, and keys must be immutable or hashable. Typical uses are remembering what you have seen (the pair-sum problem), mapping values to indices, deduplicating and caching results.

Practice. Solve Two Sum in one pass with a hash map from value to index, then Insert Delete GetRandom O(1).

Counting and grouping Core

Many problems reduce to counting: character frequencies for anagrams, the most common element, or whether one collection can be built from another. Use a counter or a fixed array when the alphabet is small.

Grouping uses a canonical key: the sorted letters of a word group anagrams together, a tuple of counts groups strings with equal character frequencies, and a normalised shape groups islands with the same shape. Choosing the right key is the whole problem.

Practice. Solve Valid Anagram, then Group Anagrams with a canonical key, and state the complexity for n words of length k.

Hashing for sequences and strings Recommended

Sets also answer questions about sequences quickly. To find the longest run of consecutive numbers in O(n), put all numbers in a set and start counting only from numbers whose predecessor is missing. To detect duplicates within a distance k, keep a sliding set of the last k values.

For strings, a rolling hash lets you compare substrings in O(1) after preprocessing, which powers substring search and finding repeated substrings. Mention collision risk and how to reduce it with a second hash.

Practice. Solve Longest Consecutive Sequence in O(n) with a set, then Palindrome Pairs using a hash map from reversed words to indices.

Stage 4 Linked lists, stacks and queues

Intermediate1–2 weeks5 topics

Goal. Manipulate pointers safely and use stacks and queues, including the monotonic variants.

Linked lists Core

A linked list is a chain of nodes, each pointing to the next. Inserting or removing at a known node is O(1), but finding a node by position is O(n). Interview problems test careful pointer handling: reversing a list, merging sorted lists, removing the n-th node from the end and reordering.

Two habits prevent most bugs: use a dummy head node so the first node needs no special case, and draw the pointers before and after each step. Reversal needs three variables: previous, current and next.

Practice. Solve Reverse Linked List and Merge Two Sorted Lists, then Reorder List, which combines finding the middle, reversing and merging.

Fast and slow pointers Core

Two pointers moving at different speeds reveal structure in a linked list without extra memory. A slow pointer moving one step and a fast pointer moving two will meet if there is a cycle; when fast reaches the end, slow is at the middle.

To find where a cycle starts, after they meet move one pointer to the head and advance both one step at a time; they meet at the cycle's start. The same idea finds a duplicate number in an array whose values point to indices.

Practice. Solve Linked List Cycle and Middle of the Linked List, then use the middle in Sort List to split the list for merge sort.

Stacks Core

A stack is last in, first out. Use it whenever the most recent item must be handled first: matching brackets, undo, evaluating expressions, and simulating recursion. Push opening brackets and pop when a closing bracket arrives; the string is valid if every pop matches and the stack ends empty.

Stacks also evaluate postfix expressions directly and convert recursive tree traversals into loops. In most languages a dynamic array works as a stack with append and pop at the end.

Practice. Solve Valid Parentheses and Evaluate Reverse Polish Notation with a single stack each, then Min Stack.

Monotonic stack Recommended

A monotonic stack keeps its elements in increasing or decreasing order. When a new element breaks the order, you pop elements, and each pop is the moment you learn that element's answer, such as its next greater element.

Every element is pushed and popped once, so the scan is O(n). Use it for next greater or smaller element, daily temperature waits, stock spans, the largest rectangle in a histogram and trapping rain water. Store indices rather than values so you can compute distances.

Practice. Solve Daily Temperatures with a decreasing stack of indices, then Largest Rectangle in Histogram.

Queues and deques Core

A queue is first in, first out, and is the engine of breadth-first search. A deque supports O(1) operations at both ends; use it as a queue in BFS, and as a monotonic deque to keep the maximum or minimum of a sliding window.

Know how to build a queue from two stacks (amortised O(1) per operation) and a stack from queues, which are common warm-up questions, and when to use a circular buffer for a fixed-size queue.

Practice. Solve Implement Queue using Stacks and explain why each element is moved at most twice.

Stage 5 Binary search

Intermediate1 week3 topics

Goal. Write bug-free binary search and apply it to search spaces that are not arrays.

Binary search on sorted data Core

Binary search halves the search range each step, finding an item in a sorted array in O(log n). The hard part is the boundaries. Pick one template and use it always: for example, search for the first index where a condition becomes true, with lo and hi meaning the answer is in the half-open range.

lo, hi = 0, len(a)
while lo < hi:
    mid = (lo + hi) // 2
    if condition(a[mid]): hi = mid
    else: lo = mid + 1
return lo   # first index where condition holds

Variants find the first or last occurrence, the insertion point, or search a rotated sorted array by checking which half is sorted.

Practice. Solve Binary Search and First Bad Version with the same template, then Search in Rotated Sorted Array.

Binary search on the answer Core

When a problem asks for the minimum or maximum value that satisfies a condition, and the condition is monotonic (if a value works, every larger value works), you can binary search over the answer itself. Each step runs a check, often greedy and O(n), so the total is O(n log range).

Classic examples: the minimum ship capacity to deliver packages in d days, the minimum eating speed to finish in h hours, or the largest minimum distance when placing items. The skill is spotting the monotonic condition and writing the check function.

Practice. Find the minimum capacity to ship weights within d days by binary searching the capacity, then try Find K Closest Elements.

Searching in structures Recommended

Binary search also works on matrices sorted by row and column, on timestamps stored per key, and on any function that changes once from false to true. Sorted lists with binary search give simple versioned key-value stores where each lookup finds the latest value at or before a time.

When the search space is implicit, define clearly what lo and hi mean and what the loop returns, and test with one and two elements, where off-by-one errors show up.

Practice. Solve Search a 2D Matrix as one sorted list, then Time Based Key-Value Store with a sorted list of timestamps per key.

Stage 6 Trees and tries

Intermediate2 weeks5 topics

Goal. Traverse trees in every order, reason recursively about subtrees, and use search trees and tries.

Binary trees and depth-first traversal Core

A binary tree is nodes with up to two children. Depth-first traversals visit nodes in preorder (node, left, right), inorder (left, node, right) or postorder (left, right, node). Most tree problems are a recursive function that combines answers from the left and right subtrees: height, diameter, path sums, balanced checks.

Decide what each call returns and what it records globally. The diameter problem, for example, returns the height of a subtree and updates a global best with left height plus right height. Practise writing traversals iteratively with a stack too, because some interviewers ask.

Practice. Solve Maximum Depth of Binary Tree, Diameter of Binary Tree and Binary Tree Maximum Path Sum, each with one recursive function.

Breadth-first traversal and level order Core

Breadth-first search visits a tree level by level using a queue. Processing the queue in batches of its current size gives you each level separately, which answers questions like the right side view, level averages, zigzag order and the width of each level.

Breadth-first search also finds the shortest path in unweighted structures, so it reappears in graphs. Converting a tree into a graph with parent links lets you search outward from any node.

Practice. Solve Binary Tree Level Order Traversal, Binary Tree Right Side View and Binary Tree Zigzag Level Order Traversal, then All Nodes Distance K in Binary Tree.

Binary search trees Core

In a binary search tree, every node's left subtree holds smaller values and its right subtree larger ones, so search, insert and delete take O(height): O(log n) if balanced, O(n) if not. An inorder traversal visits values in sorted order, which solves validation and k-th smallest problems.

Know how to validate a BST by passing down allowed ranges, find the lowest common ancestor by comparing values, and build a balanced tree from a sorted array by choosing the middle as the root.

Practice. Solve Validate Binary Search Tree and Kth Smallest Element in a BST, then Convert Sorted Array to Binary Search Tree and explain why choosing the middle keeps it balanced.

Serialisation and tree construction Recommended

Some problems ask you to turn a tree into a string and back, or to rebuild a tree from two traversals. Preorder with markers for missing children is enough to rebuild a tree uniquely; inorder plus preorder also determines it when values are distinct.

These problems test careful recursion with a shared index or an iterator over tokens. Explain the format you choose and why it is unambiguous.

Practice. Solve Construct Binary Tree from Preorder and Inorder Traversal, then Serialize and Deserialize Binary Tree with a preorder format and again with a level-order format.

Tries Recommended

A trie stores strings character by character in a tree, so all words with a common prefix share a path. Insert and search take O(L) for a word of length L, and prefix queries are natural, which makes tries ideal for autocomplete, word games and dictionary matching.

Each node holds a map or fixed array of children and an end-of-word flag. Wildcard search explores all children at a wildcard character. Tries can use a lot of memory, so mention compressed tries for large dictionaries.

Practice. Solve Implement Trie (Prefix Tree), then Design Add and Search Words Data Structure with depth-first search for wildcards, then Word Search II.

Stage 7 Heaps, intervals and greedy

Intermediate1–2 weeks4 topics

Goal. Keep the best k items efficiently, sweep over intervals and justify greedy choices.

Heaps and top k Core

A heap gives the smallest (or largest) item in O(1) and inserts or removes in O(log n). To keep the k largest items from a stream, use a min-heap of size k and pop when it grows past k; the result costs O(n log k) instead of sorting everything.

Other uses: the k closest points, scheduling by priority, and the running median with two heaps (a max-heap for the lower half and a min-heap for the upper half, kept balanced). Most languages provide a min-heap; negate values or use a comparator for a max-heap.

Practice. Solve Kth Largest Element in an Array and Top K Frequent Words with a size-k heap, then Find Median from Data Stream with two heaps.

K-way merge Recommended

Merging k sorted lists efficiently uses a heap holding the current head of each list. Pop the smallest, append it, and push the next item from the same list. Each of n items is pushed and popped once, so the total is O(n log k).

The same pattern finds the smallest range covering an element from each list, and the k-th smallest element across sorted rows of a matrix.

Practice. Solve Merge k Sorted Lists with a heap, then by merging pairs of lists, and compare the complexity. Then try Smallest Range Covering Elements from K Lists.

Intervals Core

Interval problems almost always start by sorting by start time. Then sweep: merge an interval into the previous one if they overlap, otherwise start a new one. Inserting a new interval is the same sweep with three phases: before, overlapping and after.

For the minimum number of meeting rooms, sort start and end times separately and sweep, or keep a min-heap of end times. Clarify whether intervals that touch at an endpoint overlap; it changes one comparison.

Practice. Solve Merge Intervals and Insert Interval, then Meeting Rooms II and Employee Free Time.

Greedy algorithms Core

A greedy algorithm makes the locally best choice at each step and never reconsiders. It is fast and simple, but only correct when you can argue that a greedy choice never blocks an optimal solution, often by an exchange argument: any optimal solution can be changed to include the greedy choice without getting worse.

Classic greedy problems: choosing the most non-overlapping intervals by earliest end time, jump game reachability, gas station circuits and assigning tasks with cooldowns. When you cannot justify the greedy choice, the problem probably needs dynamic programming.

Practice. Solve Jump Game, Gas Station and Non-overlapping Intervals, and write one sentence for each explaining why the greedy choice is safe.

Stage 8 Graphs

Advanced2 weeks5 topics

Goal. Model problems as graphs and apply traversal, ordering, shortest paths and union-find.

Graph representations and traversal Core

A graph is nodes connected by edges, directed or undirected, weighted or not. Store it as an adjacency list (a map from node to neighbours) for most problems; an adjacency matrix suits small dense graphs. Many problems hide a graph: a grid where cells are nodes, words that differ by one letter, or accounts linked by shared emails.

Depth-first search explores as far as possible before backtracking; breadth-first search explores level by level. Both visit every node and edge once, O(V + E). Always keep a visited set, and mark nodes when you add them to the queue, not when you pop them, to avoid duplicates.

Practice. Solve Number of Islands with both depth-first and breadth-first search, then Pacific Atlantic Water Flow by searching from the oceans inwards, and Clone Graph.

Weighted shortest paths Recommended

Dijkstra's algorithm finds shortest paths with non-negative weights: repeatedly take the closest unfinished node from a min-heap and relax its edges, for O((V + E) log V). Bellman-Ford handles negative edges by relaxing all edges V minus 1 times, and detects negative cycles. Edges of weight 0 or 1 only can use a deque instead of a heap.

Limits on the number of steps change the problem: a cheapest route with at most k stops is solved by running k rounds of Bellman-Ford style relaxation, or BFS over (node, stops) states.

Practice. Solve Cheapest Flights Within K Stops with k rounds of relaxation, and explain why plain Dijkstra fails here.

Topological sort Core

A topological order lists the nodes of a directed acyclic graph so every edge points forwards. Kahn's algorithm repeatedly removes nodes with no incoming edges using a queue; if some nodes are never removed, there is a cycle. The depth-first version adds each node after its descendants and reverses the list.

Use it for course prerequisites, build orders, task scheduling and deriving an alphabet from a sorted list of words. Processing the queue level by level tells you which tasks can run in parallel.

Practice. Solve Course Schedule and Course Schedule II with Kahn's algorithm, then Alien Dictionary.

Union-find Recommended

Union-find (disjoint set union) tracks which elements are in the same group. find returns a group's representative and union merges two groups. With path compression and union by rank or size, both are nearly O(1).

It shines when edges arrive one at a time: counting connected components, detecting the edge that creates a cycle, merging accounts, and Kruskal's minimum spanning tree algorithm, which sorts edges by weight and adds each one that joins two different groups.

Practice. Solve Number of Connected Components in an Undirected Graph and Graph Valid Tree with union-find, then Accounts Merge.

Stage 9 Backtracking and dynamic programming

Advanced2–3 weeks5 topics

Goal. Enumerate choices with backtracking, and turn overlapping subproblems into dynamic programming.

Backtracking Core

Backtracking builds candidates one choice at a time and abandons a path as soon as it cannot lead to a valid answer. The template is: if the current path is complete, record it; otherwise, for each choice, make it, recurse, then undo it.

def backtrack(path, start):
    if done(path): result.append(path[:]); return
    for i in range(start, n):
        if not valid(i): continue
        path.append(choice(i))
        backtrack(path, i + 1)
        path.pop()

Use it for subsets, permutations, combinations with a target sum, word search in a grid and puzzles such as placing queens. Prune early, sort to skip duplicates, and state the exponential complexity honestly.

Practice. Solve Subsets, Permutations and Combination Sum with the same template, then Word Search and N-Queens.

Dynamic programming fundamentals Core

Dynamic programming solves problems with overlapping subproblems and optimal substructure by solving each subproblem once and reusing the answer. Define three things before writing code: the state (what a subproblem is, such as the best answer for the first i items), the transition (how a state is built from smaller ones) and the base cases.

Write it top-down as recursion with memoisation, which is often easiest to get right, or bottom-up by filling a table in order, which avoids recursion limits and can reduce memory by keeping only the last row. The complexity is the number of states times the work per state.

Practice. Solve Climbing Stairs top-down and bottom-up, then Decode Ways, and write the state and transition in one line each.

One-dimensional dynamic programming Core

Many problems have a state indexed by position: the best result for the first i elements. Examples are the maximum sum of non-adjacent houses, counting ways to reach a total, the minimum coins to make an amount, and the longest increasing subsequence (O(n2) with a table, or O(n log n) with binary search over tails).

Watch the difference between counting combinations and counting ordered sequences: the loop order changes the answer. Clarify which the problem wants.

Practice. Solve House Robber, Coin Change and Longest Increasing Subsequence, then Combination Sum IV and explain why it counts ordered sequences.

Grid and two-dimensional dynamic programming Core

Two-dimensional states cover grids and pairs of sequences. On grids: unique paths, minimum path sum and the largest square of ones, where each cell depends on its neighbours above and to the left. On two strings: the longest common subsequence and edit distance, where dp[i][j] describes the first i characters of one and j of the other.

Draw the table for a small example and fill it by hand; the transition usually becomes obvious. Most of these can drop to one row of memory.

Practice. Solve Unique Paths and Maximal Square, then Longest Increasing Path in a Matrix with memoised depth-first search.

Knapsack, intervals and bitmasks Optional

The 0/1 knapsack pattern chooses items under a capacity limit, with state (item, remaining capacity); iterate capacity downwards to use one row. Partition-into-equal-sums problems are knapsack in disguise. Interval dynamic programming works on ranges, such as bursting balloons or the cheapest way to merge stones, building answers from shorter ranges.

Bitmask dynamic programming stores a set of used items as bits when n is about 20 or less, as in visiting every city once. Recognise these from the input size table above.

Practice. Solve Partition Equal Subset Sum with a boolean knapsack table, then Word Break.

Stage 10 Advanced topics and data structure design

Advanced1–2 weeks5 topics

Goal. Handle bits, maths and matrix problems, and design data structures that meet stated complexities.

Bit manipulation Recommended

Know the operators AND, OR, XOR, NOT and shifts. Useful facts: x & (x - 1) clears the lowest set bit, so counting how often you can do it counts set bits; x & -x isolates the lowest set bit; XOR of a number with itself is zero, so XOR of all values finds the one that appears once.

Bitmasks represent small sets compactly for subsets and bitmask dynamic programming. Mind integer sizes and signed shifts in Java and C++, and Python's unbounded integers when emulating 32-bit behaviour.

Practice. Solve Single Number with XOR, then Number of 1 Bits and Counting Bits.

Maths and matrix problems Recommended

Common maths topics: greatest common divisor with Euclid's algorithm, primes with a sieve, fast exponentiation by squaring in O(log n), modular arithmetic to keep numbers small, and integer overflow checks. Reversing digits safely requires checking overflow before multiplying.

Matrix problems test index handling: rotating a square matrix in place by transposing and reversing rows, and spiral traversal by shrinking four boundaries. Write the boundary updates carefully and test on one-row and one-column matrices.

Practice. Solve Reverse Integer with overflow checks, then Rotate Image and Spiral Matrix.

Designing data structures Core

Some problems ask you to design a class with operations at stated complexities, such as an LRU cache with O(1) get and put. The approach: list each operation and its target cost, pick structures that give each cost, and keep them in sync. An LRU cache combines a hash map from key to node with a doubly linked list ordered by recency.

Other examples include a frequency stack, a hit counter over a time window, a randomised set and an in-memory file system. Explain the invariants each structure maintains and test every operation, including on an empty structure.

Practice. Solve LRU Cache, then Maximum Frequency Stack, Design Hit Counter and Design In-Memory File System.

Range queries: segment and Fenwick trees Optional

When you need range sums or minimums while values change, prefix sums are too slow to update. A Fenwick tree (binary indexed tree) supports point updates and prefix sums in O(log n) with a few lines of code. A segment tree supports any associative range query, such as minimum or maximum, and range updates with lazy propagation.

These appear in harder interviews and competitive programming. Know when they are needed and be able to write a Fenwick tree from memory.

Practice. Implement a Fenwick tree for point updates and range sums, and test it against a brute-force version on random inputs.

String algorithms Optional

Fast substring search avoids the O(n · m) brute force. The KMP algorithm precomputes, for each prefix of the pattern, the longest proper prefix that is also a suffix, so the search never moves backwards in the text: O(n + m). Rabin-Karp compares rolling hashes of windows. The Z-algorithm computes, for each position, the longest substring starting there that matches a prefix.

Palindrome problems use expand-around-centre in O(n2), which is usually enough in interviews. Mention linear-time algorithms only if asked.

Practice. Solve Longest Palindromic Substring by expanding around each centre, then implement KMP prefix-function search.

Practice problems

Every problem below opens in the coding practice workspace, where you can write and run code in Python, Java, JavaScript or C++, use hints and compare with explained solutions. They are grouped by pattern so you can practise one idea until it sticks. New problems are added regularly.

Hashing

Two pointers

Sliding window

Stacks

Linked lists

Binary search

Trees: depth-first

Trees: breadth-first

Binary search trees

Heaps

Intervals and greedy

Graphs: traversal and shortest paths

Graphs: ordering and union-find

Backtracking

Dynamic programming

Maths, matrices and bits

Designing data structures

Twelve-week plan

About ten hours a week: an hour on weekdays and a longer session at the weekend. Use the study plan to schedule it and the progress page to keep a streak and see which problems are due for review.

  1. Weeks 1–2Foundations, arrays and hashing
    • Learn Big-O, recursion and your language's standard library (stages 1 to 3).

    • Solve two easy problems a day on arrays, strings and hash maps, using the six-step method out loud.

  2. Weeks 3–4Two pointers, windows, stacks and lists
    • Cover two pointers, sliding windows, prefix sums, stacks, queues and linked lists (stages 2 and 4).

    • Move to medium problems. Time each one and note the pattern you used.

  3. Weeks 5–6Binary search and trees
    • Binary search on arrays and on the answer, then binary trees, search trees and tries (stages 5 and 6).

    • Write tree traversals from memory, both recursively and with an explicit stack or queue.

  4. Weeks 7–8Heaps, intervals, greedy and graphs
    • Heaps, intervals and greedy choices, then graph traversal, topological sort, shortest paths and union-find (stages 7 and 8).

    • Practise grid problems with breadth-first search until the template is automatic.

  5. Weeks 9–10Backtracking and dynamic programming
    • Backtracking, then dynamic programming from one-dimensional to grid, knapsack and subsequence problems (stage 9).

    • For each dynamic programming problem, write the state, the transition and the base case before any code.

  6. Weeks 11–12Mixed practice and mock interviews
    • Solve mixed problems without knowing the pattern in advance, and review stage 10 topics.

    • Run at least six timed mock interviews of 45 minutes, ideally with a friend acting as interviewer.

    • Redo every problem you struggled with; spaced review turns patterns into habits.

Interview questions

Beyond solving problems, interviewers ask conceptual questions about data structures and algorithms. Answer out loud before opening each one.

What is the difference between an array and a linked list, and when would you use each?Entry

An array stores elements contiguously, so access by index is O(1) and scanning is fast thanks to the CPU cache, but inserting or deleting in the middle shifts elements and costs O(n). A linked list stores nodes connected by pointers, so inserting or removing at a known node is O(1), but reaching the k-th element is O(n) and each node carries pointer overhead. I use arrays by default, and linked lists when I need frequent splicing at known positions, such as the recency list inside an LRU cache.

How does a hash map work, and what happens when two keys collide?Entry

A hash map computes a hash of the key and maps it to a bucket in an array. Lookups go straight to the bucket, so they average O(1). Collisions happen when two keys land in the same bucket; they are handled by chaining, where each bucket holds a small list or tree of entries, or by open addressing, where the map probes other slots. When the load factor gets too high the map resizes and rehashes all keys, which is O(n) but rare enough that operations stay O(1) amortised. A poor hash function or adversarial keys can degrade lookups to O(n).

Why can comparison-based sorting not be faster than O(n log n)?Mid

A comparison sort must distinguish between all n factorial possible orderings of the input. Each comparison has two outcomes, so the algorithm is a binary decision tree, and a tree with n factorial leaves has height at least log2 of n factorial, which is on the order of n log n. Counting sort and radix sort beat this bound because they do not compare elements; they use the values themselves, which works when keys are small integers or have a bounded number of digits.

When would you choose breadth-first search over depth-first search?Entry

I choose breadth-first search when I need the shortest path in an unweighted graph or the minimum number of steps, because it visits nodes in order of distance, and when I want to process things level by level. Depth-first search is simpler for exploring everything, detecting cycles, topological ordering and problems that naturally recurse, such as tree path problems. Memory differs too: BFS can hold a whole level, which is wide in bushy graphs, while DFS holds one path but can overflow the stack on very deep graphs if written recursively.

How do you decide whether a problem needs dynamic programming or a greedy algorithm?Mid

Both need optimal substructure. Greedy also needs the greedy-choice property: taking the locally best option never rules out an optimal solution, which I try to prove with an exchange argument. If I can find a small counterexample where the greedy choice fails, as with coin change using unusual coin values, I switch to dynamic programming, which considers all choices for each subproblem. Dynamic programming is safer but costs more time and memory, so I try greedy first when there is a clear ordering such as earliest end time.

Explain how a heap supports finding the k largest elements in a stream.Mid

I keep a min-heap of size k holding the k largest elements seen so far, with the smallest of them at the top. For each new element, if the heap has fewer than k items I push it; otherwise, if the element is larger than the top, I replace the top. Each operation is O(log k), so n elements cost O(n log k) time and O(k) memory, which is much better than sorting when k is small and the stream is large or unbounded. The heap top is always the k-th largest so far.

What is the time complexity of a recursive Fibonacci function, and how do you improve it?Entry

The naive version calls itself twice for each n, so the calls form a binary tree with roughly 1.6 to the power n nodes: exponential time, with O(n) stack depth. The same values are computed many times. Memoisation stores each result the first time, reducing time to O(n). A bottom-up loop keeping only the last two values gives O(n) time and O(1) memory. Matrix exponentiation or fast doubling reach O(log n) if asked.

How would you detect a cycle in a directed graph?Mid

One way is depth-first search with three states per node: unvisited, in progress and done. If the search reaches a node that is in progress, there is an edge back into the current path, which is a cycle. Another way is Kahn's topological sort: repeatedly remove nodes with no incoming edges; if some nodes can never be removed, they are part of a cycle. Both are O(V + E). For undirected graphs, union-find or tracking the parent in DFS works instead.

What is amortised analysis? Give an example.Mid

Amortised analysis looks at the average cost per operation over a worst-case sequence, rather than the worst single operation. Appending to a dynamic array is the standard example: most appends are O(1), but when the array is full it doubles its capacity and copies everything, which is O(n). Because each doubling pays for as many cheap appends as it copies, the total cost of n appends is O(n), so each append is O(1) amortised. A queue built from two stacks is another example.

Your solution is O(n squared) and the input has 100,000 elements. How do you approach optimising it?Mid

At 100,000 elements, n squared is 10 billion operations, which is far too slow, so I need O(n log n) or O(n). I look for the repeated work in the inner loop. If it searches for something, a hash map or sorting with binary search can replace it. If it recomputes sums over ranges, prefix sums or a sliding window help. If it looks for the next larger element, a monotonic stack does it in one pass. If it needs the best item seen so far, a heap or running variable works. I state the new complexity and confirm it fits before coding.

Explain the trade-offs between recursion and iteration.Entry

Recursion often matches the shape of the problem, such as trees, divide and conquer and backtracking, so the code is shorter and easier to prove correct. Its costs are function call overhead and stack memory proportional to the depth, which can overflow on deep inputs, for example a linked list of a million nodes or a skewed tree. Iteration with an explicit stack or queue avoids those limits and gives more control, at the cost of more code. In interviews I write recursion when depth is bounded and mention the iterative alternative.

How would you find the median of a stream of numbers?Senior

I keep two heaps: a max-heap with the smaller half of the numbers and a min-heap with the larger half, balanced so their sizes differ by at most one. Each new number goes into the max-heap if it is not larger than its top, otherwise into the min-heap, then I rebalance by moving one top across if needed. The median is the top of the larger heap, or the average of both tops when sizes are equal. Insertion is O(log n) and reading the median is O(1). If values come from a small range, counting buckets give O(range) queries with less memory.

Common mistakes

  • Solving hundreds of problems at random. Practise by pattern first, then mix, and review the ones you got wrong.
  • Reading solutions too early. Struggle for at least 20 to 30 minutes, then read only a hint, then try again.
  • Coding before agreeing the approach. Say the idea and its complexity first; it saves the interview when the idea is wrong.
  • Skipping complexity analysis. Every solution should end with its time and space cost, stated without being asked.
  • Practising in silence. Interviews are spoken; rehearse explaining your thinking from the first day.
  • Relying on running code to find bugs. Trace by hand first; many interviews do not let you run code.
  • Ignoring edge cases: empty input, one element, duplicates, negative numbers, overflow and very large inputs.
  • Memorising solutions instead of understanding why they work. Interviewers change details to check exactly this.

Ready-for-interview checklist

  • I can state the time and space complexity of any solution I write, including recursive ones.
  • I know the cost of every operation on arrays, hash maps, linked lists, stacks, queues, heaps, trees and tries.
  • I can write binary search, breadth-first search, depth-first search and topological sort from memory without bugs.
  • I can recognise two pointers, sliding window, prefix sums, monotonic stack, heap and interval patterns from the statement.
  • I can write a backtracking solution with correct pruning and undo steps.
  • I can define the state, transition and base case for common dynamic programming problems.
  • I solve most medium problems in 30 minutes, with clean code and tests.
  • I explain my thinking out loud from clarification to testing, and use hints well.

Related pages

FAQ

How many problems should I solve before interviews?

Quality beats quantity. Around 150 to 250 well-chosen problems, solved by pattern and reviewed until you can redo them, is enough for most companies. Someone who has solved 150 problems and can explain each one beats someone who has skimmed 600. Track the patterns you are weak in and practise those rather than adding more easy problems.

Which programming language should I use for coding interviews?

Use the language you know best. Python is popular because it is concise and has a rich standard library, which saves time. Java and C++ are equally accepted. Avoid switching languages shortly before interviews; fluency with the standard library matters more than the language itself.

How long does it take to prepare data structures and algorithms?

From a basic programming level, about three to four months at around ten hours a week covers everything on this page. If you studied computer science and have done this before, four to six weeks of focused practice is usually enough to get back up to speed. Consistency matters more than intensity: an hour a day beats a long session once a week.

Do I need to know advanced topics such as segment trees?

For most interviews, no. The core and recommended topics on this page cover the large majority of questions. Advanced topics such as segment trees, Fenwick trees and string algorithms appear occasionally at companies with harder loops and in competitive programming. Learn them after you are solid on everything else.

What should I do when I am stuck in an interview?

Say what you are thinking. Go back to a brute-force solution and look for repeated work, try a smaller example by hand, and check the patterns that match the clues in the statement. If the interviewer gives a hint, take it and build on it; using hints well is scored positively. Silence is the only thing that cannot be scored.

Practise while you learn.Solve interview problems in the browser, with hints and a timer.
CodingSQLSystem design
No Comment
Add Comment
comment url