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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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 n | Target complexity | Typical approaches |
|---|---|---|
| up to 10–12 | O(n!) or O(2n · n) | Try every ordering or subset with backtracking |
| up to 20–25 | O(2n) | Subsets, bitmask dynamic programming, meet in the middle |
| up to 100–500 | O(n3) | Three nested loops, interval dynamic programming, all-pairs shortest paths |
| up to 5,000 | O(n2) | Pairs, two-dimensional dynamic programming |
| up to 105–106 | O(n log n) or O(n) | Sorting, heaps, binary search, hash maps, two pointers, sliding windows, prefix sums |
| above 108 | O(log n) or O(1) | Maths, binary search on the answer |
Cost of common operations
| Structure | Access or search | Insert | Delete | Notes |
|---|---|---|---|---|
| Dynamic array | O(1) by index, O(n) search | O(1) amortised at end, O(n) in middle | O(n) in middle | Contiguous, cache friendly |
| Hash map or set | O(1) average | O(1) average | O(1) average | No order; O(n) worst case with many collisions |
| Linked list | O(n) | O(1) at a known node | O(1) at a known node | Good for splicing, poor for random access |
| Stack, queue, deque | O(1) at the ends | O(1) | O(1) | Use a deque for both ends |
| Binary heap | O(1) peek min or max | O(log n) | O(log n) pop | Building from n items is O(n) |
| Balanced search tree | O(log n) | O(log n) | O(log n) | Keeps order: floor, ceiling, range queries |
| Trie | O(L) for a word of length L | O(L) | O(L) | Prefix queries |
| Union-find | nearly O(1) | nearly O(1) union | not supported | With 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 implies | Try |
|---|---|
| Sorted array, find a pair or triple with a target sum | Two pointers |
| Longest or shortest contiguous subarray or substring with a property | Sliding window |
| Sum of a range, or count subarrays with a given sum | Prefix sums with a hash map |
| Have I seen this value, or count frequencies | Hash map or set |
| Sorted input, or minimise the maximum or maximise the minimum | Binary search, or binary search on the answer |
| Next greater or smaller element, or spans | Monotonic stack |
| Matching brackets, undo, nested structure | Stack |
| Top k, k-th largest, merge k sorted lists, running median | Heap |
| Overlapping ranges, meetings, merging times | Sort by start, then sweep |
| Shortest path in an unweighted grid or graph, minimum steps | Breadth-first search |
| Weighted shortest path with non-negative weights | Dijkstra's algorithm |
| Dependencies or ordering constraints | Topological sort |
| Connected groups, merging sets, detecting a cycle as edges arrive | Union-find |
| All combinations, permutations or subsets | Backtracking |
| Count the ways, or the best value, with overlapping subproblems | Dynamic programming |
| Prefix lookups over many words | Trie |
| Linked list cycle or middle element | Fast 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.
- Stage 1FoundationsBeginner · 1–2 weeks · 4 topics
- Stage 2Arrays and stringsBeginner · 2 weeks · 6 topics
- Stage 3HashingBeginner · 1 week · 3 topics
- Stage 4Linked lists, stacks and queuesIntermediate · 1–2 weeks · 5 topics
- Stage 5Binary searchIntermediate · 1 week · 3 topics
- Stage 6Trees and triesIntermediate · 2 weeks · 5 topics
- Stage 7Heaps, intervals and greedyIntermediate · 1–2 weeks · 4 topics
- Stage 8GraphsAdvanced · 2 weeks · 5 topics
- Stage 9Backtracking and dynamic programmingAdvanced · 2–3 weeks · 5 topics
- Stage 10Advanced topics and data structure designAdvanced · 1–2 weeks · 5 topics
Stage 1 Foundations
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
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
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
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
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 holdsVariants 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
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
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
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.
Shortest paths with breadth-first search Core
In an unweighted graph, breadth-first search finds the shortest path because it reaches nodes in order of distance. Track distance per node or process the queue level by level. Multi-source BFS starts with several nodes in the queue at once, solving problems like the time for rot to spread from many sources.
When the state includes more than position, such as remaining moves or keys collected, search over (position, extra) states. Count the states to make sure the search fits in time.
Practice. Solve Rotting Oranges with multi-source BFS and Shortest Path to Get Food with single-source BFS, then Minimum Knight Moves and Word Ladder.
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
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
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
- Contains DuplicateEasy · Array · Hash Table · Sorting
- Longest PalindromeEasy · Greedy · Hash Table · String
- Majority ElementEasy · Array · Hash Table · Sorting
- Ransom NoteEasy · Hash Table · String
- Two SumEasy · Array · Hash Table
- Valid AnagramEasy · Hash Table · Sorting · String
- Contiguous ArrayMedium · Array · Hash Table · Prefix Sum
- Group AnagramsMedium · Array · Hash Table · String
- Longest Consecutive SequenceMedium · Array · Hash Table · Union Find
- Set Matrix ZeroesMedium · Array · Hash Table · Matrix
- Subarray Sum Equals KMedium · Array · Hash Table · Prefix Sum
- Valid SudokuMedium · Array · Hash Table · Matrix
- First Missing PositiveHard · Array · Hash Table
- Palindrome PairsHard · Array · Hash Table · String
Two pointers
- Backspace String CompareEasy · Stack · String · Two Pointers
- Move ZeroesEasy · Array · Two Pointers
- Squares of a Sorted ArrayEasy · Array · Sorting · Two Pointers
- Valid PalindromeEasy · String · Two Pointers
- 3SumMedium · Array · Sorting · Two Pointers
- 3Sum ClosestMedium · Array · Sorting · Two Pointers
- Container With Most WaterMedium · Array · Greedy · Two Pointers
- Find the Duplicate NumberMedium · Array · Binary Search · Two Pointers
- Next PermutationMedium · Array · Two Pointers
- Rotate ArrayMedium · Array · Math · Two Pointers
- Sort ColorsMedium · Array · Sorting · Two Pointers
- Trapping Rain WaterHard · Array · Dynamic Programming · Two Pointers
Sliding window
- Find All Anagrams in a StringMedium · Hash Table · Sliding Window · String
- Longest Repeating Character ReplacementMedium · Hash Table · Sliding Window · String
- Longest Substring Without Repeating CharactersMedium · Hash Table · Sliding Window · String
- Minimum Window SubstringHard · Hash Table · Sliding Window · String
- Sliding Window MaximumHard · Array · Queue · Sliding Window
Stacks
- Valid ParenthesesEasy · Stack · String
- Asteroid CollisionMedium · Array · Simulation · Stack
- Basic Calculator IIMedium · Math · Stack · String
- Daily TemperaturesMedium · Array · Monotonic Stack · Stack
- Decode StringMedium · Recursion · Stack · String
- Evaluate Reverse Polish NotationMedium · Array · Math · Stack
- Min StackMedium · Design · Stack
- Basic CalculatorHard · Math · Stack · String
- Largest Rectangle in HistogramHard · Array · Monotonic Stack · Stack
- Longest Valid ParenthesesHard · Dynamic Programming · Stack · String
Linked lists
- Linked List CycleEasy · Hash Table · Linked List · Two Pointers
- Merge Two Sorted ListsEasy · Linked List · Recursion
- Middle of the Linked ListEasy · Linked List · Two Pointers
- Palindrome Linked ListEasy · Linked List · Recursion · Two Pointers
- Reverse Linked ListEasy · Linked List · Recursion
- Add Two NumbersMedium · Linked List · Math · Recursion
- Odd Even Linked ListMedium · Linked List
- Remove Nth Node From End of ListMedium · Linked List · Two Pointers
- Reorder ListMedium · Linked List · Stack · Two Pointers
- Rotate ListMedium · Linked List · Two Pointers
- Sort ListMedium · Divide and Conquer · Linked List · Sorting
- Swap Nodes in PairsMedium · Linked List · Recursion
- Merge k Sorted ListsHard · Divide and Conquer · Heap · Linked List
- Reverse Nodes in k-GroupHard · Linked List · Recursion
Binary search
- Binary SearchEasy · Array · Binary Search
- First Bad VersionEasy · Binary Search
- Find K Closest ElementsMedium · Array · Binary Search · Two Pointers
- Find Minimum in Rotated Sorted ArrayMedium · Array · Binary Search
- Random Pick with WeightMedium · Binary Search · Design · Prefix Sum
- Search a 2D MatrixMedium · Array · Binary Search · Matrix
- Search in Rotated Sorted ArrayMedium · Array · Binary Search
- Time Based Key-Value StoreMedium · Binary Search · Design · Hash Table
- Median of Two Sorted ArraysHard · Array · Binary Search · Divide and Conquer
Trees: depth-first
- Balanced Binary TreeEasy · DFS · Recursion · Tree
- Diameter of Binary TreeEasy · DFS · Recursion · Tree
- Invert Binary TreeEasy · BFS · DFS · Tree
- Maximum Depth of Binary TreeEasy · BFS · DFS · Tree
- Same TreeEasy · BFS · DFS · Tree
- Subtree of Another TreeEasy · DFS · Recursion · Tree
- Symmetric TreeEasy · BFS · DFS · Tree
- Construct Binary Tree from Preorder and Inorder TraversalMedium · Divide and Conquer · Hash Table · Tree
- Lowest Common Ancestor of a Binary TreeMedium · DFS · Recursion · Tree
- Path Sum IIMedium · Backtracking · DFS · Tree
- Path Sum IIIMedium · DFS · Hash Table · Tree
- Binary Tree Maximum Path SumHard · DFS · Dynamic Programming · Tree
Trees: breadth-first
- All Nodes Distance K in Binary TreeMedium · BFS · DFS · Tree
- Binary Tree Level Order TraversalMedium · BFS · Queue · Tree
- Binary Tree Right Side ViewMedium · BFS · DFS · Tree
- Binary Tree Zigzag Level Order TraversalMedium · BFS · Queue · Tree
- Maximum Width of Binary TreeMedium · BFS · Queue · Tree
- Serialize and Deserialize Binary TreeHard · BFS · String · Tree
Binary search trees
- Convert Sorted Array to Binary Search TreeEasy · Array · Binary Search Tree · Divide and Conquer
- Inorder Successor in BSTMedium · Binary Search Tree · Tree
- Kth Smallest Element in a BSTMedium · Binary Search Tree · DFS · Tree
- Lowest Common Ancestor of a Binary Search TreeMedium · Binary Search Tree · DFS · Tree
- Validate Binary Search TreeMedium · Binary Search Tree · DFS · Tree
Heaps
- K Closest Points to OriginMedium · Array · Heap · Sorting
- Kth Largest Element in an ArrayMedium · Array · Divide and Conquer · Heap
- Top K Frequent WordsMedium · Hash Table · Heap · String
- Find Median from Data StreamHard · Design · Heap · Sorting
- Smallest Range Covering Elements from K ListsHard · Array · Heap · Sliding Window
Intervals and greedy
- Best Time to Buy and Sell StockEasy · Array · Dynamic Programming · Greedy
- Meeting RoomsEasy · Array · Intervals · Sorting
- Gas StationMedium · Array · Greedy
- Insert IntervalMedium · Array · Intervals
- Jump GameMedium · Array · Dynamic Programming · Greedy
- Largest NumberMedium · Array · Greedy · String
- Meeting Rooms IIMedium · Heap · Intervals · Sorting
- Merge IntervalsMedium · Array · Intervals · Sorting
- Non-overlapping IntervalsMedium · Array · Greedy · Sorting
- Task SchedulerMedium · Array · Greedy · Hash Table
- Employee Free TimeHard · Array · Heap · Sorting
Graphs: traversal and shortest paths
- Flood FillEasy · Array · BFS · DFS
- 01 MatrixMedium · BFS · Dynamic Programming · Matrix
- Cheapest Flights Within K StopsMedium · BFS · Dynamic Programming · Graph
- Clone GraphMedium · BFS · Graph · Hash Table
- Minimum Knight MovesMedium · BFS · Math · Matrix
- Number of IslandsMedium · BFS · DFS · Matrix
- Pacific Atlantic Water FlowMedium · Array · BFS · Matrix
- Rotting OrangesMedium · BFS · Matrix · Queue
- Shortest Path to Get FoodMedium · Array · BFS · Matrix
- Bus RoutesHard · Array · BFS · Hash Table
- Word LadderHard · BFS · Hash Table · String
Graphs: ordering and union-find
- Accounts MergeMedium · Array · Hash Table · Union Find
- Course ScheduleMedium · BFS · Graph · Topological Sort
- Course Schedule IIMedium · BFS · Graph · Topological Sort
- Graph Valid TreeMedium · DFS · Graph · Union Find
- Minimum Height TreesMedium · BFS · Graph · Topological Sort
- Number of Connected Components in an Undirected GraphMedium · DFS · Graph · Union Find
- Alien DictionaryHard · Graph · String · Topological Sort
Backtracking
- Combination SumMedium · Array · Backtracking · Recursion
- Generate ParenthesesMedium · Backtracking · Recursion · String
- Letter Combinations of a Phone NumberMedium · Backtracking · Hash Table · String
- PermutationsMedium · Array · Backtracking · Recursion
- SubsetsMedium · Array · Backtracking · Bit Manipulation
- Word SearchMedium · Array · Backtracking · String
- N-QueensHard · Array · Backtracking
- Sudoku SolverHard · Array · Backtracking · Matrix
- Word Search IIHard · Backtracking · Matrix · Trie
Dynamic programming
- Climbing StairsEasy · Dynamic Programming · Math · Recursion
- Coin ChangeMedium · Array · BFS · Dynamic Programming
- Combination Sum IVMedium · Array · Dynamic Programming
- Decode WaysMedium · Dynamic Programming · String
- House RobberMedium · Array · Dynamic Programming
- Longest Increasing SubsequenceMedium · Array · Binary Search · Dynamic Programming
- Longest Palindromic SubstringMedium · Dynamic Programming · String · Two Pointers
- Maximal SquareMedium · Array · Dynamic Programming · Matrix
- Maximum Product SubarrayMedium · Array · Dynamic Programming
- Maximum SubarrayMedium · Array · Divide and Conquer · Dynamic Programming
- Partition Equal Subset SumMedium · Array · Dynamic Programming
- Unique PathsMedium · Dynamic Programming · Math · Matrix
- Word BreakMedium · Dynamic Programming · Hash Table · String
- Longest Increasing Path in a MatrixHard · DFS · Matrix · Topological Sort
- Maximum Profit in Job SchedulingHard · Array · Binary Search · Dynamic Programming
Maths, matrices and bits
- Add BinaryEasy · Bit Manipulation · Math · String
- Counting BitsEasy · Bit Manipulation · Dynamic Programming
- Longest Common PrefixEasy · Array · String
- Missing NumberEasy · Array · Bit Manipulation · Math
- Number of 1 BitsEasy · Bit Manipulation · Math
- Palindrome NumberEasy · Math
- Reverse BitsEasy · Bit Manipulation
- Roman to IntegerEasy · Hash Table · Math · String
- Single NumberEasy · Array · Bit Manipulation
- Pow(x, n)Medium · Divide and Conquer · Math · Recursion
- Product of Array Except SelfMedium · Array · Prefix Sum
- Reverse IntegerMedium · Math
- Rotate ImageMedium · Array · Math · Matrix
- Spiral MatrixMedium · Array · Matrix · Simulation
- String to Integer (atoi)Medium · String
Designing data structures
- Implement Queue using StacksEasy · Design · Queue · Stack
- Design Add and Search Words Data StructureMedium · Design · String · Trie
- Design Hit CounterMedium · Design · Queue
- Encode and Decode StringsMedium · Array · Design · String
- Implement Trie (Prefix Tree)Medium · Design · Hash Table · Trie
- Insert Delete GetRandom O(1)Medium · Array · Design · Hash Table
- LRU CacheMedium · Design · Hash Table · Linked List
- Design In-Memory File SystemHard · Design · Hash Table · Trie
- Maximum Frequency StackHard · Design · Hash Table · Stack
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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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
- Coding practiceSolve problems in the browser with hints and explained solutions.
- System design guideThe other half of most technical loops.
- Software Engineer roadmapThe full path to a software engineering offer.
- Company interview guidesHow coding rounds differ at each company.
- Study planTurn this roadmap into a daily schedule.
- My progressStreaks, solved counts and problems due for review.
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.