What Quant Coding Interviews Actually Test
Quant coding interviews look like FAANG interviews on the surface but differ in three important ways. First, the bar is higher - top quant firms expect harder problems solved cleaner, faster. Second, the problems are often finance-flavoured (order books, time series, risk computations) which gives candidates with prior exposure a real advantage. Third, the firms care about latency and memory in a way that FAANG companies don't - your solution being O(n log n) is necessary but not sufficient if you allocate on the hot path.
This guide collects 20 worked examples drawn from recent Hudson River Trading, Jane Street, Citadel, Two Sigma, DRW, Jump and XTX interviews. For broader context, see our quant developer career guide, C++ in quantitative finance and Python fundamentals for quant finance.
Section 1: Data Structures (Questions 1-7)
1. Stream median
Implement a class that supports add(x) and median() over a growing stream.
import heapq class StreamMedian: def __init__(self): self.lo = [] # max-heap (negated) self.hi = [] # min-heap def add(self, x): heapq.heappush(self.lo, -x) heapq.heappush(self.hi, -heapq.heappop(self.lo)) if len(self.hi) > len(self.lo): heapq.heappush(self.lo, -heapq.heappop(self.hi)) def median(self): if len(self.lo) > len(self.hi): return -self.lo[0] return (-self.lo[0] + self.hi[0]) / 2
Two heaps balanced at size difference ≤ 1. Add: O(log n); median: O(1).
2. LRU cache
Implement a least-recently-used cache with O(1) get and put.
Approach: Doubly linked list (most-recent at head) plus hash map from key to list node. On get, splice the node to the head. On put, if at capacity, evict the tail.
3. Order book
Implement an order book supporting add(side, price, qty), cancel(order_id), and get_top_of_book() in O(log N).
Approach: Two sorted maps (e.g., std::map in C++): bids descending by price, asks ascending. Each price level is a doubly linked list of orders (for time priority). Hash map from order_id to a tuple (side, price, list_node) for O(1) cancellation lookup.
4. Sliding window maximum
Given a stream of integers and a window size N, return the rolling maximum in O(n) total.
from collections import deque def rolling_max(arr, n): window = deque() out = [] for i, x in enumerate(arr): while window and arr[window[-1]] <= x: window.pop() window.append(i) if window[0] <= i - n: window.popleft() if i >= n - 1: out.append(arr[window[0]]) return out
Monotonic deque. Each element added and removed at most once.
5. Top-K elements stream
Given a stream of integers, return the K largest seen so far on demand.
Approach: Min-heap of size K. On each new element, if it's larger than the heap minimum, pop and push. O(log K) per insert.
6. Concurrent hash map
Design a thread-safe hash map for mostly-read workloads.
Approach: RW lock at the bucket level, or a fully lock-free design (e.g., open addressing with atomic CAS). Discuss the trade-offs - bucket-level locking is simpler; lock-free is faster under high contention but harder to debug.
7. Skip list
Why might a quant firm prefer a skip list over a balanced BST for an order book?
Answer: Simpler implementation, easier concurrency, and constant-factor performance is often comparable to BSTs. Skip lists also have natural support for range queries which is useful for things like "all bids within X bp of best."
Section 2: Algorithms (Questions 8-14)
8. Maximum subarray sum
Given an array of integers, return the maximum sum of any contiguous subarray.
Answer: Kadane's algorithm. Track running max and current sum; reset current to zero if it goes negative. O(n) time.
9. Two sum target (sorted)
Given a sorted array, return whether any two elements sum to a target.
Answer: Two pointers. Move from each end. Move left right when sum is too small, right left when too large. O(n).
10. Find duplicates in O(1) space
Given an array of N integers in range [1, N-1], find any duplicate without modifying the array.
Answer: Floyd's tortoise and hare cycle detection. Treat the array as a function: position i maps to value arr[i]. There's a cycle because of the duplicate; find it.
11. Median of two sorted arrays
Given two sorted arrays of total length n+m, find the median in O(log(min(n,m))).
Answer: Binary search on the partition point. Carefully handle the edge cases. Worth practising the implementation - this is a notorious "easy idea, hard implementation" problem.
12. Merge K sorted lists
Given K sorted lists with N total elements, merge them in O(N log K).
Answer: Min-heap of K elements (one head from each list). Pop, push next from same list. O(N log K).
13. Intervals merging
Given a list of intervals, merge overlapping ones.
Approach: Sort by start. Iterate; if current overlaps last in result, extend; else append. O(n log n).
14. Longest increasing subsequence
Given an array, find the length of the longest strictly-increasing subsequence in O(n log n).
Answer: Patience sort. Maintain an array of "tail values" of increasing subsequences of each length. For each new element, binary search for the first tail >= it and replace.
Section 3: Concurrency and Low-Latency (Questions 15-20)
15. Producer-consumer queue
Implement a thread-safe single-producer single-consumer ring buffer.
Approach: Atomic head and tail indices. Producer uses release semantics on store of head. Consumer uses acquire semantics on load of head. The release-acquire pair guarantees the consumer sees the data the producer wrote before publishing.
template <typename T, size_t N> class SPSCQueue { std::atomic<size_t> head{0}; std::atomic<size_t> tail{0}; T buffer[N]; public: bool push(const T& item) { size_t h = head.load(std::memory_order_relaxed); size_t next = (h + 1) % N; if (next == tail.load(std::memory_order_acquire)) return false; buffer[h] = item; head.store(next, std::memory_order_release); return true; } bool pop(T& item) { size_t t = tail.load(std::memory_order_relaxed); if (t == head.load(std::memory_order_acquire)) return false; item = buffer[t]; tail.store((t + 1) % N, std::memory_order_release); return true; } };
16. False sharing
Two threads each increment their own counter. The counters happen to be in the same cache line. What goes wrong, and how do you fix it?
Answer: Cache line ping-pong. Each write invalidates the other thread's cached copy, forcing a memory fetch. Performance can be 10-100x slower than expected. Fix: pad the counters to separate cache lines (typically 64 bytes), or use alignas(64).
17. Memory ordering
Explain the difference between memory_order_relaxed, memory_order_acquire, memory_order_release, and memory_order_seq_cst.
Answer: Relaxed: no ordering guarantees, only atomicity. Acquire: prevents subsequent reads/writes from being reordered before the load. Release: prevents prior reads/writes from being reordered after the store. Seq_cst: total global ordering across all atomic operations. Use the weakest that suffices.
18. Cache-friendly traversal
Two ways to traverse an N×N matrix: by rows or by columns. Which is faster, and why?
Answer: Row-major traversal is faster (assuming row-major storage). Sequential memory access is cache-friendly; column traversal jumps by N elements per access, busting the cache. Performance gap can be 5-10x for large matrices.
19. Branch prediction
You have a tight loop with an if that's true less than 1% of the time. How do you optimise?
Answer: Mark the branch with [[unlikely]] (C++20) or __builtin_expect (GCC/Clang) so the compiler optimises for the common case. Alternative: restructure to avoid the branch entirely. Modern CPUs predict well already, so always profile first.
20. Memory pool
Why might a low-latency system use a custom memory pool instead of malloc?
Answer: Three reasons. (1) Latency consistency: malloc has unpredictable tail latency due to fragmentation, system calls, and lock contention. (2) Cache locality: pool-allocated objects can be co-located. (3) No global synchronisation: a thread-local pool avoids contention with other threads.
How to Use This Guide
For Python-track candidates, focus on questions 1-14. For C++ engineering tracks (HRT, Jump, Radix), questions 15-20 are essential and the C++ memory model questions are the most common single source of failure.
For broader prep:
- Quant interview questions hub
- Python fundamentals for quant finance
- C++ in quantitative finance
- Hardware acceleration for quant
For firm-specific interview content with these patterns:
- Hudson River Trading interview (deep on lock-free)
- Jane Street interview (algorithmic)
- Citadel interview (broad)
- Jump Trading interview (C++ depth)
Practise the questions Quant Coding Interview Questions: 20 Real Examples 2026 actually asks
Reading about the interview is one thing - sitting one is another. Quantt's interactive coding tests are modelled on the same problem types that show up in firms like Jane Street, Citadel, Hudson River and Optiver. Run real Python in the browser, get instant feedback, and benchmark yourself against the bar.
Free to start - no credit card required