skip to content

Data structures & algorithms

27 roadmaps833 questionsupdated

Everything you need to reason about data structures and algorithms the way coding interviews demand: complexity analysis, the core structures, the algorithm families built on them, and the recurring problem-solving patterns. Interviewers lean on DSA because it shows how you model a problem, weigh trade-offs, and defend the efficiency of your solution under pressure.

on this pageshow

guide

overview

~2 min

Data structures and algorithms is the subject most coding rounds are built on. The interviewer hands you a problem and watches three things: how you turn the prose into a model (a sequence, a set of pairs, a graph), which structure you pick to hold that model, and whether you can defend the cost of the result in time and space. A working answer matters; explaining why it is correct and why it is fast enough matters as much, and at senior levels it usually matters more. The subject splits into four layers. The first is the measuring stick: [complexity analysis](/topics/found-dsa-complexity), the notation and reasoning every other section uses to state a cost. The second is the structures themselves: [arrays and strings](/topics/found-dsa-arrays-strings), linked lists, stacks and queues, [hash tables](/topics/found-dsa-hash-tables), trees, heaps and graphs, each defined by the operations it makes cheap and the ones it makes expensive. The third is the algorithm families that run on them: sorting, binary search, recursion and backtracking, [dynamic programming](/topics/found-dsa-dynamic-programming), greedy choice, and the bit-level and number-theory toolkit. The fourth is the layer candidates skip and interviewers weigh: the recurring [problem patterns](/topics/found-dsa-algo-patterns) such as two pointers and sliding windows, and the [problem-solving strategy](/topics/found-dsa-problem-solving) that shapes what you say in the first five minutes. Learn complexity first, because every later answer ends with a cost you have to justify. Then work through arrays, hashing and the linear structures, since most problems start there; trees and graphs next, because that is where recursion stops being optional; the paradigms and patterns last, once you can recognise the structures they operate on. Questions run from a junior asking why an operation is constant time to a principal asked what a guarantee actually promises and when it breaks. The same idea often appears at several depths, so come back to a section as your level rises rather than treating it as finished.

primer

A handful of ideas carry the whole subject. With these solid, most questions below become applications rather than facts to memorise. - **Cost is a growth rate, not a stopwatch reading.** Asymptotic notation describes how work scales as input grows, which is why it hides constant factors and why two algorithms with the same bound can still differ noticeably in practice. Every answer should end with a time bound and a space bound, and you should know whether each is worst case, expected or amortized. Those are three different promises, and interviewers check which one you mean. - **A structure is a bundle of operation costs.** Arrays buy constant-time positional access with contiguous memory and pay for it when inserting in the middle. Linked structures buy cheap splicing and pay for it on access. Hashing buys expected constant-time lookup by key and gives up order. Balanced trees keep order at a logarithmic price. Choosing a structure means naming the operation the problem repeats most and picking whatever makes that one cheap. - **Invariants make algorithms correct.** A heap's parent-to-child ordering, a search tree's ordering across whole subtrees, binary search's shrinking candidate range, a sliding window's validity condition: each is a property you establish, preserve at every step and rely on at the end. Interviewers probe the invariant because a candidate who can state it can usually repair a broken implementation. - **Recursion is the shared engine.** Tree walks, graph search, divide and conquer, backtracking and top-down dynamic programming are the same machinery (a base case, progress toward it, a combining step) pointed at different problems. A clear picture of the call stack pays off in every one of those sections. - **Repeated work is the thing to remove.** Most optimisations eliminate recomputation: storing results of subproblems that recur, updating a running quantity instead of rebuilding it, remembering what has already been seen in a set or map. When a brute force is too slow, first ask what it computes more than once. - **Constraints predict the intended solution.** The input sizes and limits in a problem statement indicate roughly which complexity class is expected, and so which families of approach are worth considering. Reading them before designing is a skill, not a trick.

Asymptotic notation
The bounds (big-O above, big-Omega below, big-Theta tight) that describe how cost grows with input size, setting aside constant factors and smaller terms.
Worst-case complexity
The cost bound over the most expensive input of a given size; the reading an interviewer assumes unless you say expected or amortized.
Expected complexity
Cost averaged over a distribution of inputs or over an algorithm's own random choices. Hash lookups and randomized quicksort are normally quoted this way.
Amortized cost
Average cost per operation across any sequence of operations, letting a rare expensive step be spread over many cheap ones with no probability assumption.
Auxiliary space
Memory used beyond the input itself, recursion stack included; what claims of working in place or in constant space normally refer to.
Invariant
A property that holds before and after every step of an algorithm or every operation on a structure, used both to argue correctness and to locate bugs.
Load factor
The ratio of stored entries to buckets in a hash table; crossing a chosen threshold triggers a resize that keeps expected lookup cost constant.
Collision
Two distinct keys landing in the same bucket. Every hash table has them; the resolution scheme, chaining or open addressing, decides what they cost.
Heap property
The ordering rule a binary heap keeps between each parent and its children, which puts the minimum or maximum at the root without sorting the rest.
Balanced search tree
A search tree whose height is held logarithmic in its size by rotations or splits, so ordered operations stay logarithmic whatever the insertion order.
Adjacency list
A graph representation storing each vertex's neighbours; its space grows with vertices plus edges, which suits the sparse graphs most problems describe.
Topological order
A linear ordering of a directed graph's vertices in which every edge points forward; one exists exactly when the graph has no cycle.
Overlapping subproblems
The condition dynamic programming exploits: a recursive decomposition reaches the same smaller problem many times, so storing each result once removes the repetition.
Optimal substructure
An optimal solution is assembled from optimal solutions to its subproblems. Dynamic programming and greedy algorithms both rely on it; greedy also needs a provably safe local choice.
Stable sort
A sort that keeps elements with equal keys in their original relative order, which matters when sorting by one key and then another.
Backtracking
Depth-first construction of candidate solutions that abandons a partial candidate as soon as it cannot lead to a valid one.

The sections are not independent chapters; they lean on each other in a fairly fixed order. **Complexity analysis is the common language.** Every other section states its results in it, and several are best read as worked examples of one technique: dynamic arrays and hash-table resizing illustrate amortized cost, recursive sorts illustrate recurrences, and hashing illustrates the gap between expected and worst-case bounds. **The linear structures are building blocks.** Stacks and queues are implemented on top of arrays or linked nodes, and they return as the frontier of graph traversal: a queue for breadth-first search, a stack or the call stack for depth-first. A hash table paired with a doubly linked list gives a cache with an eviction order, and a binary heap is an array read as a tree. **Trees sit between lists and graphs.** A tree is a connected graph with no cycles and a chosen root, so tree traversals are the simple case of graph traversal; the extra bookkeeping graphs need comes from cycles and shared paths. Search trees are also what you reach for when a hash table's lack of order becomes the problem. **The paradigms are ways of organising a search.** Brute force enumerates candidates; backtracking enumerates them while pruning dead branches; divide and conquer splits the input and combines the results; dynamic programming notices that subproblems overlap and stores them; greedy commits to one choice per step and needs a proof that it never has to reconsider. Many interview discussions are really about which of these a problem admits, and the sections on [greedy algorithms](/topics/found-dsa-greedy) and [dynamic programming](/topics/found-dsa-dynamic-programming) both spend time on the boundary between the two. **Sorting and searching are infrastructure.** Sorting is often a preprocessing step that turns a harder problem into a linear scan, and binary search applies wherever a monotone yes-or-no condition exists, over a sorted array or over a range of candidate answers. **Patterns and strategy sit on top.** Two pointers, sliding windows, prefix sums and monotonic stacks are compact recipes that pair a structure with an invariant, and they only make sense once the structures are familiar. [Problem-solving strategy](/topics/found-dsa-problem-solving) then ties everything to the round itself: clarifying the task, stating a baseline, choosing a target complexity from the constraints, and narrating the trade-off you made.

  1. Complexity Analysis →

    Every answer ends with a time and space bound, so learn to derive and state one before studying the things it measures.

  2. Arrays & Strings →

    Most problems arrive as an array or a string, and their memory layout sets the costs every other structure is compared against.

  3. Hashing & Hash Tables →

    The usual tool for turning a quadratic search into a linear one, and a structure whose guarantees candidates routinely overstate.

  4. Recursion & Backtracking →

    Trees, graphs, divide and conquer and dynamic programming all assume a working model of recursive calls; build it before them.

  5. Trees →

    Recursion applied to a real structure: traversals, the search-tree invariant, why balancing matters, and the step up to graphs.

  6. Interview Problem Patterns →

    With the structures familiar, the patterns show how a structure and an invariant combine to solve whole families of problems.

  • Stating a complexity without saying whether it is worst case, expected or amortized; hash lookups and dynamic-array appends are where this gets challenged.

  • Quoting logarithmic lookup for a binary search tree without mentioning balance; built from already-ordered input, an unbalanced tree degrades into a chain.

  • Leaving the recursion stack out of a space bound: a recursive solution with no explicit allocation still uses memory proportional to its depth.

  • Hunting for the clever solution in silence instead of stating a correct brute force first; the interviewer cannot credit an approach they never heard.

  • Accepting a greedy rule because it passes the examples, with no exchange argument and no search for a counterexample; greedy failures are silent.

  • Binary search boundary slips: mixing inclusive and exclusive bounds, a loop condition that never terminates, or a midpoint computation that overflows fixed-width integers.

  • Treating a graph like a tree and skipping visited-tracking, which loops on cycles or expands shared vertices many times.

  • Picking a structure by habit rather than by the operation the problem repeats; the right choice starts from which operation has to be cheap.

  • Comparing floating-point results for exact equality, or ignoring integer overflow on sums and products near the type's limit.

The same few choices recur across nearly every section, and naming the one you are making is often worth more than the code. - **Time versus space.** Most speed-ups spend memory: a set of seen values, a memo table, a precomputed prefix array. Say what you spent and whether the constraints allow it; sometimes the expected answer is the slower, constant-space version. - **Worst case versus typical case.** Quicksort, hash tables and unbalanced search trees are fast in the common case and slow on adversarial input. Whether that matters depends on who controls the input, and an interviewer may ask exactly that. - **Order versus lookup speed.** Hashing gives up ordering for expected constant-time access; a balanced tree or a sorted array keeps range queries and nearest neighbours available at a logarithmic price. - **Preprocessing versus per-query cost.** Sorting once, building prefix sums or an index pays upfront so that many later queries are cheap. It is a good trade when queries are many and the data rarely changes, and a poor one for a single query. - **Asymptotic bound versus constant factors.** Contiguous memory, cache behaviour and small inputs can make the theoretically slower option faster in practice, which is why many hybrid library sorts hand short ranges to insertion sort. - **Clarity versus cleverness.** Recursion is often clearer and iteration safer against deep stacks; a bit trick is compact but harder to verify. In a round, prefer the version you can explain and test.

Some shapes appear across many sections under different names; recognising them is how you place an unfamiliar problem quickly. - **Shrink the candidate set.** Binary search on sorted data, binary search over a range of possible answers, and two pointers converging on a sorted array all discard part of the search space per step using a monotone condition. - **Maintain a running summary.** Sliding windows, prefix sums, running extremes and furthest-reach counters keep a small piece of state updated per element instead of rescanning. - **Expand a frontier.** Breadth-first search, depth-first search, Dijkstra's algorithm and level-order traversal differ mainly in which container holds the frontier: a queue, a stack or a priority queue. - **Choose, recurse, undo.** Subsets, permutations, combinations and constraint puzzles share one backtracking skeleton; problems differ in the choice set and the pruning rule. - **Define a state and a transition.** Dynamic programming problems on grids, knapsacks, sequences and intervals yield once you can say what a table cell means and which smaller cells it reads. - **Keep the best k.** A heap capped at k elements answers top-k and k-way merge questions in a single pass. - **Merge groups as you go.** Union-find tracks connectivity as edges arrive and underlies cycle detection in undirected graphs and Kruskal's spanning-tree algorithm. The [pattern and structure selection](/topics/found-dsa-algo-patterns-selection) section works the reverse direction: from a problem statement to the pattern it hides.

explore

→ has its own guide

report an issue with this guide →

questions

833 · 16 sections

What does an amortized O(1) guarantee actually promise about a single operation?

level: juniorimportance: must knowfreq 72%
basics
~20 s

Amortized O(1) promises nothing about one call, which may cost O(n). It bounds the total cost of any n operations at O(n) — a worst-case guarantee over a whole sequence, not an average over likely inputs.

open as a page

Why is appending to a growth-doubling dynamic array O(1) amortized when one append copies everything?

level: juniorimportance: must knowfreq 88%
basics
~20 s

Doubling makes each resize twice as rare as the last, so the copies across n appends sum to 1+2+4+...+n, which stays under 2n. That is O(n) total work spread over n appends, hence O(1) per append on average over the sequence.

open as a page

An input bound of 100,000 bookings — what time complexity should you target, and why?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Target O(n log n) or better. Quadratic work at n = 100,000 is about 10^10 operations, far past the rough budget of 10^8 simple operations per second, while n log n lands near 1.7 million — comfortably inside it.

open as a page

Why does deduplicating invitee addresses with a membership check on a growing collection cost O(n^2)?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Each membership check scans everything kept so far, so the check at step k costs O(k), not O(1). Summing 1 through n gives O(n^2). A hash-based set makes each check expected O(1), so the whole pass becomes O(n).

open as a page

Why do two sequential loops over n records cost O(n), but one nested inside the other O(n^2)?

level: juniorimportance: must knowfreq 88%
basics
~20 s

Loops side by side add their trip counts: n + n = 2n, and constants drop, so it stays O(n). Nesting multiplies instead: the inner loop restarts in full for every outer step, giving n * n = O(n^2).

open as a page

A dynamic array's size falls from a million to twelve — why doesn't its memory footprint fall too?

level: juniorimportance: must knowfreq 66%
basics
~20 s

A dynamic array tracks two separate numbers: size, the elements in use, and capacity, the slots allocated. Removing elements lowers size only. The underlying buffer stays as large as it ever grew until something explicitly shrinks it.

open as a page

Why does a growable array track both a size and a capacity, and what happens when they are equal?

level: juniorimportance: must knowfreq 82%
basics
~20 s

Size is how many elements are stored; capacity is how many slots the underlying block can hold. Appending when size equals capacity forces allocating a larger block, copying every stored element into it, and releasing the old one.

open as a page

After in-place compaction with a write pointer, why must the caller be given a returned length?

level: juniorimportance: must knowfreq 74%
basics
~10 s

In-place compaction never shrinks the array, so survivors occupy only a prefix and stale values still sit in the tail. The returned write count is the only signal of how many entries are valid.

open as a page

Why does an in-place array reversal need only n/2 swaps rather than n?

level: juniorimportance: must knowfreq 72%
basics
~10 s

Each swap places two elements at once, so n/2 swaps fix all n positions. Looping over every index instead swaps each pair twice, which undoes the reversal and hands back the original array.

open as a page

Why does a flat pixel buffer index as y*width+x, and what breaks if you write x*width+y?

level: juniorimportance: must knowfreq 65%
basics
~20 s

A flat row-major buffer stores each row as width consecutive slots, so the cell at column x, row y lives at ywidth+x. Writing xwidth+y addresses the transposed cell: harmless-looking on square images, corrupting or overrunning everything else.

open as a page

In a linked list, why is there no address arithmetic to reach the k-th node?

level: juniorimportance: must knowfreq 85%
basics
~20 s

A linked list's nodes are separately allocated and scattered in memory, so there is no base address plus fixed stride to compute. Each node knows only where the next one lives, so reaching index k means following k links.

open as a page

Why does a dummy head node remove the special case for deleting the first element?

level: juniorimportance: must knowfreq 66%
basics
~20 s

A dummy head is a permanent node placed before the first real element, so every real node has a predecessor. Deletion is always relink-the-predecessor, which means the first element needs no branch of its own.

open as a page

In a singly-linked list, why is appending at the end O(n), and what makes it O(1)?

level: juniorimportance: must knowfreq 72%
basics
~20 s

Appending is O(n) when only a head reference is kept, because the last node is reachable only by walking the whole chain. Storing a tail reference alongside the head makes append O(1) in any of the three variants.

open as a page

How do you detect whether a singly linked list has a cycle, and why does a plain walk hang?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Walk two references, one hopping one node per step and one hopping two. If they meet, the list has a cycle; if the fast one runs off the end, it does not. A plain walk never reaches an end, so it spins forever.

open as a page

How does a deque give you both stack and queue behavior, and what does each of its four operations cost?

level: juniorimportance: must knowfreq 62%
basics
~20 s

A deque supports push and pop at both ends, each constant time. Pushing and popping at the same end gives LIFO stack behavior; pushing at one end and popping at the other gives FIFO queue behavior.

open as a page

Array-backed vs linked-node stack: what does a single push cost in each?

level: juniorimportance: must knowfreq 72%
basics
~20 s

Linked-node push is O(1) worst case: allocate a node and link it to the head. Array-backed push is O(1) amortized: usually one slot write, but a full buffer forces copying every element into a larger block.

open as a page

In a queue built from two stacks, when may elements move from the inbound to the outbound stack?

level: juniorimportance: must knowfreq 74%
basics
~20 s

Only when the outbound stack is empty. Pushing the inbound stack's contents onto a non-empty outbound stack puts newer arrivals above older ones and destroys first-in-first-out order. Standard implementations drain the inbound stack completely in that one transfer.

open as a page

Why does level-order traversal of a company org chart use a queue instead of a stack?

level: juniorimportance: must knowfreq 78%
basics
~20 s

A queue hands nodes back in the order they were discovered, so every person at one depth is expanded before anyone a depth lower. A stack returns the most recent discovery first, which dives down a single reporting chain instead.

open as a page

Why is dequeuing from the front of an array-backed queue O(n), and what does that cost a backlog?

level: juniorimportance: must knowfreq 72%
basics
~20 s

Removing the element at index 0 slides every remaining element one slot toward the front, so a single dequeue costs O(n). Draining a backlog of n items that way costs about n^2/2 moves in total.

open as a page

In a bloom filter, what does a 'yes' answer guarantee and what does a 'no' answer guarantee?

level: juniorimportance: must knowfreq 48%
basics
~20 s

A bloom filter's 'no' is certain: that item was never added. Its 'yes' means only 'probably present' — a fraction of queries for items that were never added still come back positive. Negatives are facts, positives are hints.

open as a page

In an O(1) LRU cache, why isn't a hash map alone enough, and what does the doubly linked list add?

level: juniorimportance: must knowfreq 78%
basics
~20 s

The hash map gives O(1) lookup from key to node but knows nothing about recency. The doubly linked list orders nodes by last use, so the eviction victim sits at a known end and unlinking it costs O(1).

open as a page

What does an ordered map give you that a hash map does not, and what do you pay for it?

level: juniorimportance: must knowfreq 78%
basics
~20 s

An ordered map keeps its keys in sorted order, so it supports in-order iteration, range scans between two keys, and nearest-key lookups. You pay O(log n) on every insert, lookup and delete instead of a hash map's expected O(1).

open as a page

In a linear-probing hash table, how does a lookup find a key that collided when it was inserted?

level: juniorimportance: must knowfreq 62%
basics
~20 s

Linear probing puts a colliding key in the next free slot, so lookup replays that walk: start at the home slot and step forward comparing keys, stopping only at an empty slot, never at the first non-matching key.

open as a page

In separate chaining, what happens when two keys hash to the same bucket, and what does a lookup then cost?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Both keys stay: the bucket holds a list, and the new entry is linked into that list. A lookup indexes the bucket in constant time, then walks the chain comparing full keys, so its cost grows with the chain's length.

open as a page

How does tree recursion change when a node holds a list of children instead of left and right?

level: juniorimportance: must knowfreq 72%
basics
~10 s

The two hardcoded recursive calls become one loop over the children list, and the null-child check becomes an empty-children-list check. Every node is still visited exactly once, so a full traversal is still O(n).

open as a page

In an AVL tree, what is a node's balance factor and which values are legal?

level: juniorimportance: must knowfreq 72%
basics
~20 s

A node's balance factor is its left subtree's height minus its right subtree's height. An AVL tree is valid when every node's factor is -1, 0 or +1 — a bound on heights, not on node counts.

open as a page

What do a red-black tree's color invariants guarantee, and is the tree perfectly balanced?

level: juniorimportance: must knowfreq 70%
basics
~20 s

Red-black rules — no red node has a red child, and every root-to-leaf path crosses equally many black nodes — cap height near 2·log n. That is bounded, not perfectly balanced: one branch may be twice as deep as another.

open as a page

In a binary tree, what is the difference between the height of a node and its depth?

level: juniorimportance: must knowfreq 76%
basics
~20 s

Depth counts edges from the root down to the node; height counts edges from the node down to its deepest descendant. Depth is fixed by where a node sits, while height depends on whatever hangs below it.

open as a page

In preorder, inorder and postorder traversal of a binary tree, what actually changes between them?

level: juniorimportance: must knowfreq 88%
basics
~20 s

All three walk the left subtree before the right; only the position of the node's own visit moves — before both subtree walks (preorder), between them (inorder), or after both (postorder). All three are depth-first and all cost O(n).

open as a page

Why is extract-min from a min-heap O(log n) when the minimum already sits at the root?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Finding the minimum is O(1) — it sits at the root. Removing it costs O(log n): the last element is moved into the empty root slot and sifted down through the tree's height until the heap property holds again.

open as a page

Why is bottom-up heapify cheaper than inserting n items one at a time into a heap?

level: juniorimportance: must knowfreq 72%
basics
~20 s

Bottom-up heapify turns an array of n items into a heap in O(n) time, while n successive inserts cost O(n log n) in the worst case. Same heap, lower cost, whenever every item is available up front.

open as a page

In a min-heap held in an array, is that array sorted, and what does the heap property actually guarantee?

level: juniorimportance: must knowfreq 82%
basics
~20 s

A min-heap's array is not sorted. The property constrains only parent versus child, so every root-to-leaf path is non-decreasing while siblings may sit in any order. Only index 0 is guaranteed: it holds the minimum.

open as a page

What operations define the priority queue abstraction, and how does it differ from a FIFO queue?

level: juniorimportance: must knowfreq 80%
basics
~20 s

A priority queue supports three operations: insert an item with a priority, peek at the top-priority item, and extract that item. A FIFO queue hands back items in arrival order; a priority queue hands back the most urgent one first.

open as a page

A standard-library priority queue only pops the smallest key, but your scheduler must serve the highest priority first. What are your options?

level: juniorimportance: must knowfreq 74%
basics
~10 s

Give the queue a reversed comparison function, or push negated numeric keys. The reversed comparison is safer and self-documenting; negation works only for numeric keys and forces every read site to remember the flip.

open as a page

Why doesn't a minimum spanning tree give the cheapest route between two given nodes?

level: juniorimportance: must knowfreq 62%
basics
~20 s

A minimum spanning tree minimizes one global sum: the total weight of the edges keeping every node connected. It promises nothing about any specific pair, so its path between two nodes can cost more than a direct link.

open as a page

Why does an adjacency matrix use O(V^2) space while an adjacency list uses O(V+E)?

level: juniorimportance: must knowfreq 80%
basics
~20 s

An adjacency matrix reserves a cell for every pair of vertices, so its size depends only on V, never on the edge count. An adjacency list stores one entry per vertex plus one per actual edge, so it grows with E.

open as a page

In a warehouse robot's floor grid, what plays the role of nodes and edges in a graph?

level: juniorimportance: must knowfreq 76%
basics
~20 s

Each open cell is a node; an edge joins two cells one step apart, up, down, left or right. No edge list exists anywhere: a direction array plus a bounds-and-blocked check produces a cell's neighbors on demand.

open as a page

Why does Bellman-Ford relax every edge V-1 times rather than once?

level: juniorimportance: must knowfreq 72%
basics
~20 s

After k passes over all edges, Bellman-Ford holds the best route that uses at most k edges. When no negative cycle exists, a best route never repeats a vertex, so it spans at most V-1 edges.

open as a page

What does Dijkstra's algorithm compute on a travel-time road map, and in what order does it finalize vertices?

level: juniorimportance: must knowfreq 84%
basics
~20 s

Dijkstra computes the minimum total travel time from one source to every reachable intersection - cheapest total weight, not fewest road segments. Vertices are finalized in non-decreasing distance order, so once one is popped its distance never changes.

open as a page

Heapsort sorts in place — where does the heap live, and how does the array change as it runs?

level: juniorimportance: must knowfreq 72%
basics
~20 s

Heapsort builds its max-heap inside the input array itself — nothing extra is allocated. The array splits into a heap prefix and a growing sorted suffix; each round swaps the root to the boundary and shrinks the heap by one.

open as a page

Why is merge sort O(n log n) on every input, including data that arrives already sorted?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Merge sort always halves the input until single-element runs remain, then merges back up. That gives about log2 n levels, and every level moves all n elements once, so the total is n log n whatever the input order.

open as a page

Quicksort averages O(n log n) — what input drives it to O(n^2), and why?

level: juniorimportance: must knowfreq 88%
basics
~20 s

Quicksort degrades to O(n^2) when every pivot splits off almost nothing — classically ordered input against a fixed first- or last-element pivot. Partitioning then peels one element per level, giving n levels of linear work instead of log n.

open as a page

Bubble sort and selection sort are both O(n^2) — what does one pass of each accomplish?

level: juniorimportance: must knowfreq 72%
basics
~10 s

A bubble sort pass swaps out-of-order adjacent pairs, carrying the largest remaining value to the end. A selection sort pass scans the unsorted region for its minimum and places it with one swap.

open as a page

Why does insertion sort run in near-linear time on nearly-ordered input but quadratic time on reversed input?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Insertion sort's work is proportional to how far elements must move. Each element shifts past only the larger elements before it, so nearly-ordered input costs a few shifts per element; reversed input forces every element past every predecessor.

open as a page

In a sorted array, what does a lower bound search return when the target value is absent?

level: juniorimportance: must knowfreq 72%
basics
~20 s

A lower bound search returns the first index whose element is greater than or equal to the target. For an absent key that index is exactly where the value would be inserted to keep the array sorted. It never reports failure.

open as a page

Why does a plain binary search return an arbitrary index when the sorted array holds duplicate keys?

level: juniorimportance: must knowfreq 74%
basics
~20 s

A plain binary search returns the moment a midpoint matches, so which member of a run of equal keys comes back depends only on where the splits fell. The leftmost occurrence requires searching on after a hit.

open as a page

Why does binary search need only about log2(n) comparisons where a linear scan needs n?

level: juniorimportance: must knowfreq 88%
basics
~20 s

Each comparison discards half of the remaining candidates, so the range shrinks n, n/2, n/4, down to one. The number of halvings needed to reach a single candidate is log2(n), so that many comparisons suffice.

open as a page

Why do binary search implementations compute mid as lo + (hi - lo) / 2 instead of (lo + hi) / 2?

level: juniorimportance: must knowfreq 70%
basics
~20 s

Adding lo and hi can overflow a fixed-width signed integer once indices grow large, wrapping negative and yielding an out-of-range midpoint. Computing lo + (hi - lo) / 2 keeps every intermediate value inside the valid index range.

open as a page

Why is linear search still O(n) even though it exits early on the first match?

level: juniorimportance: must knowfreq 80%
basics
~20 s

Linear search is O(n) because the bound is set by the worst case: a match in the last position, or no match at all, forces a scan of every element. Early exit improves lucky runs, not the growth rate.

open as a page

Merge sort and quicksort are both divide and conquer — which phase does each spend its per-level work in?

level: juniorimportance: must knowfreq 82%
basics
~20 s

Quicksort spends in the divide step: partitioning is a linear pass, and when the halves return there is nothing to combine. Merge sort splits by index in constant time and pays its linear pass when combining.

open as a page

What makes a recursive algorithm divide-and-conquer rather than plain recursion?

level: juniorimportance: must knowfreq 68%
basics
~20 s

Divide-and-conquer splits a problem into two or more subproblems of the same kind on a fraction of the input, solves them independently, and combines their answers. A function that merely calls itself does none of that by default.

open as a page

Why does enumerating all subsets of n flags give 2^n results but all orderings give n!?

level: juniorimportance: must knowfreq 85%
basics
~20 s

Subsets ask one yes/no question per item: n independent binary decisions, so 2^n outcomes. Orderings fill n positions from a shrinking pool: n choices, then n-1, then n-2, down to 1, which multiplies out to n!.

open as a page

In grid path backtracking, why must a cell be un-marked after its recursive branch returns?

level: juniorimportance: must knowfreq 72%
basics
~20 s

A cell is marked only to keep the path currently being built from reusing it. Once that branch returns, the cell is no longer on the path, so leaving it marked wrongly blocks every other path that needs to pass through it.

open as a page

Why prune a backtracking branch as soon as the running total exceeds the budget rather than at the leaf?

level: juniorimportance: must knowfreq 68%
basics
~20 s

Testing only at the leaf still walks every branch to the bottom. Testing on entry deletes a whole subtree in one return: once the running total is over budget, more items can never bring it back down.

open as a page

In a right-and-down-only grid, why is a cell's route count the sum of the cells above and left?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Every route into a cell takes its last step from either the cell above or the cell to its left. Those two sets of routes are disjoint and together cover every route, so the two counts simply add.

open as a page

In 0/1 knapsack, what does dp[i][w] hold and which two candidates does the recurrence compare?

level: juniorimportance: must knowfreq 78%
basics
~20 s

dp[i][w] is the best total value reachable using only the first i items within a capacity of w. The recurrence takes the larger of leaving item i out, dp[i-1][w], and taking it, value[i] + dp[i-1][w - weight[i]], when it fits.

open as a page

In minimum-coins change-making, what does dp[a] hold and how do you mark unreachable amounts?

level: juniorimportance: must knowfreq 78%
basics
~10 s

dp[a] holds the fewest coins summing exactly to amount a: one plus the smallest dp[a - c] over each denomination c that fits. Amounts no combination reaches carry an infinity sentinel, never 0.

open as a page

Why does greedily picking the highest-value non-adjacent ad slots miss the optimal schedule?

level: juniorimportance: must knowfreq 74%
basics
~20 s

Greedy commits to a big slot before knowing what it blocks: taking a slot forbids both neighbours, so two merely good neighbours can outvalue one great slot. The take-or-skip recurrence best(i) = max(best(i-1), value(i) + best(i-2)) weighs both futures.

open as a page

In an edit distance table over two contact names, what does dp[i][j] mean and what fills row 0?

level: juniorimportance: must knowfreq 72%
basics
~20 s

dp[i][j] is the edit distance between the first i characters of one name and the first j of the other — the indexes are prefix LENGTHS, not positions. Row 0 holds 0,1,2,...,j: turning nothing into a j-character prefix costs j insertions.

open as a page

Why must a Huffman code be prefix-free, and what breaks in decoding without it?

level: juniorimportance: must knowfreq 70%
basics
~20 s

Prefix-free means no codeword is the beginning of another, so a decoder reading bits one at a time always knows exactly where a symbol ends. Without that property the same bit stream decodes several different ways.

open as a page

Why does earliest-finish-time beat shortest-duration when picking the most non-overlapping talks?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Choosing the talk that finishes earliest leaves the largest possible remaining window for everything after it, and that rule is provably optimal. Shortest-duration is not: one short talk can straddle the seam between two longer talks and cost you a slot.

open as a page

Why does one furthest-reach counter decide whether you can cross a river of stones, each stone i allowing a leap of at most a[i] forward?

level: juniorimportance: must knowfreq 72%
basics
~20 s

Reachability is monotone: standing on stone i makes every stone up to i + a[i] reachable too. So one pass keeping the maximum of i + a[i], abandoning the crossing as soon as the index passes that maximum, settles it in O(n).

open as a page

In an exchange argument for a greedy algorithm, what do you swap and what must the swap show?

level: juniorimportance: must knowfreq 55%
basics
~20 s

An exchange argument starts from any optimal solution, finds the first point where it disagrees with greedy, and swaps greedy's choice in. The swap must stay feasible and no worse, so some optimal solution agrees with greedy.

open as a page

Why can nearest-stop greedy routing, taking the closest undelivered address each time, produce a poor total route?

level: juniorimportance: must knowfreq 68%
basics
~20 s

Each nearest-stop pick is cheapest right now but reshapes what remains. Cheap early hops strand far-apart addresses for the end, so a chain of locally best moves need not add up to the best route.

open as a page

In cyclic sort over values 1..n, why does one final scan reveal a missing value?

level: juniorimportance: must knowfreq 48%
basics
~20 s

Cyclic sort moves every value v to index v-1, so once placement finishes index i must hold i+1. The first index that breaks that rule names the absent value outright, with no extra lookup structure.

open as a page

Why can't a singly linked chain be palindrome-checked by converging pointers from both ends?

level: juniorimportance: must knowfreq 66%
basics
~20 s

A singly linked chain has no backward pointers, so nothing can walk from the tail inward. The standard fix splits the chain at the middle, reverses the back half in place, then compares the two halves node by node.

open as a page

Why must overlapping intervals be sorted by start before a single-pass merge?

level: juniorimportance: must knowfreq 82%
basics
~20 s

Sorting by start guarantees any interval that could overlap the one being built arrives before the pass moves past it. In arrival order, an overlapping slot can appear after you already emitted an interval, so a single pass misses merges.

open as a page

What single condition tells you two half-open intervals [start, end) overlap?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Two half-open intervals overlap exactly when a.start < b.end and b.start < a.end. That pair of strict comparisons is the negation of the only two ways intervals can miss each other: one finishing at or before the other begins.

open as a page

How does a sweep line find the maximum number of sessions open at once in a login/logout log?

level: juniorimportance: must knowfreq 70%
basics
~20 s

A sweep line throws away the intervals and keeps only their boundaries: +1 at each login coordinate, -1 at each logout. Sort those events by coordinate, scan once with a running sum, and remember the largest sum seen.

open as a page

In a permission bitmask, how do you grant, revoke and test one flag without disturbing the others?

level: juniorimportance: must knowfreq 68%
basics
~20 s

Grant with OR: mask | FLAG. Revoke by ANDing the complement: mask & ~FLAG. Test membership with (mask & FLAG) != 0. XOR toggles rather than clears, so it is the wrong operator for revoke.

open as a page

Why does an 8-bit two's-complement integer range from -128 to 127 rather than -127 to 127?

level: juniorimportance: must knowfreq 75%
basics
~20 s

Two's complement gives the top bit a weight of -128, so the 256 patterns split into 128 negatives (-128 to -1) and 128 non-negatives. Zero uses one non-negative pattern, leaving only 127 positives — so -128 has no positive counterpart.

open as a page

How do you clear bit k of a status word with a mask, leaving every other bit untouched?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Use n = n & ~(1 << k). The shifted mask holds a single 1 at position k; inverting it gives all ones except there, so the AND forces that bit to 0 and leaves the rest unchanged.

open as a page

Why does extracting a 12-bit length field from a packed 32-bit header need both a right shift and a mask?

level: juniorimportance: must knowfreq 68%
basics
~20 s

The shift moves the field down to bit 0 so it reads as a number; the mask clears the neighbouring fields still sitting above it. Shift alone leaves garbage on top, mask alone leaves the value scaled.

open as a page

Permutations vs combinations: which counts a top-3 podium from 30 entrants?

level: juniorimportance: must knowfreq 62%
basics
~20 s

Permutations count arrangements where order matters; combinations count selections where it does not. A ranked top-3 podium from 30 entrants gives 30 x 29 x 28 = 24,360 outcomes; an unordered shortlist of three gives only 4,060.

open as a page

After reading a problem's constraints, what must your plan state before you write any code?

level: juniorimportance: must knowfreq 78%
basics
~20 s

A usable plan names the constraints that actually bind (input size, memory ceiling, whether data can be re-read), the time and space class you are targeting, the concrete steps and the data you keep, and what you rejected and why.

open as a page

Why state a brute-force solution aloud before optimizing in a coding interview?

level: juniorimportance: must knowfreq 80%
basics
~20 s

A stated brute force proves you understood the problem, gives the interviewer a correct baseline to score, and becomes your fallback if the clever idea collapses. Silence while hunting for the optimal answer reads as being stuck.

open as a page

Why restate the problem and probe edge cases before writing any code in an interview?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Clarifying is the cheapest place to be wrong. A couple of minutes spent restating the task and asking about empty input, single elements, duplicates and negative values beats thirty minutes spent solving the wrong problem.

open as a page

A report recomputes a day's running total from scratch on every query - how do you optimize it, and what do you pay?

level: juniorimportance: must knowfreq 72%
basics
~20 s

Compute the totals once and answer each query by lookup: q queries over n rows drop from O(q*n) to one O(n) pass plus O(1) per query. You pay extra memory, and staleness whenever the underlying rows change.

open as a page

In a coding interview, how do you narrate a fork between two approaches before writing code?

level: juniorimportance: must knowfreq 75%
basics
~20 s

State each approach in a sentence or two, name the cost that separates them, say which one you would take and why, then ask the interviewer to confirm before you write a line of code.

open as a page