Citadel Software Engineer Phone Screen Questions
18+ questions from real Citadel Software Engineer Phone Screen rounds, reported by candidates who interviewed there.
What does the Citadel Phone Screen round test?
The Citadel phone screen typically lasts 45-60 minutes and evaluates core Software Engineer fundamentals. Candidates should expect 1-2 algorithmic problems, basic system design discussion at senior levels, and questions about relevant experience. The goal is to confirm technical competence before bringing candidates onsite.
Top Topics in This Round
Citadel Software Engineer Phone Screen Questions
The first interview asked about merging k lists, but binary search can't be used because the space complexity needs to be O(k) instead of O(n). I just received my Superday offer after a month. Anyone
Recruiter reach-out, 90 minutes, 3 questions, all coding. The following content requires a score higher than 150. You can already view it. The first question was Li Kou, exactly the same as Liu Siqi.
The interview lasted 45 minutes. The interviewer seemed unfriendly, and I felt a lot of pressure. After scrutinizing my resume, they started asking technical questions. The first question was a simple
Citadel | Software Engineer | NYC | Feb 2020 [Reject]
Overview Interviewing for software engineering role at NYC office. Has 4 total rounds. ## Round 1 ### Question Tell me about the a exciting problem you had to solve recently. ### Question Write a producer class, which...
## Problem Simulate the spread of infection across cells in a grid, tracking time steps to full infection. ## Likely LeetCode equivalent Similar to LC 994 Rotting Oranges. ## Tags graph, bfs, matrix, citadel
## Problem Find the K closest points to the origin (or to each other) in a 2D plane. ## Likely LeetCode equivalent Same as LC 973 K Closest Points to Origin. ## Tags heap, math, citadel
## Problem A large file is split into numbered parts and uploaded in arbitrary order. Each part has a part number (1-indexed), a checksum, and a byte payload. Implement a validator that (1) accepts parts as they arrive, (2) identifies missing part numbers once an `end` signal is received, and (3) verifies checksums, reporting corrupt parts. ```python class FilePartsValidator: def __init__(self, expected_parts: int): ... def receive_part(self, part_num: int, checksum: str, data: bytes) -> None: ... def finalize(self) -> dict: """ Returns { "missing": [part_nums], "corrupt": [part_nums], "valid": bool } """ ``` **Example:** ``` v = FilePartsValidator(3) v.receive_part(1, "abc", b"hello") v.receive_part(3, "bad", b"world") # checksum mismatch v.finalize() # -> {"missing": [2], "corrupt": [3], "valid": False} ``` ## Follow-ups 1. How do you compute and verify the checksum — MD5, SHA-256, or CRC32? What are the tradeoffs? 2. If parts can be retransmitted (duplicates), how does your model handle re-receipt of a valid part? 3. How would you reassemble the file in order from received parts with minimal memory overhead? 4. What streaming approach avoids holding all parts in memory simultaneously?
## Problem Implement a cache that evicts the least frequently used item (LFU). ## Likely LeetCode equivalent Same as LC 460 LFU Cache. ## Tags hash_table, design, citadel, lfu
Citadel SWE Phone - Horizon Max (Sliding Window/Heap)
## Problem Find the maximum value within a sliding window of fixed size across a sequence. ## Likely LeetCode equivalent Same as LC 239 Sliding Window Maximum. ## Tags sliding_window, heap, citadel
## Problem Machine configurations are stored in a hierarchical format: a `base` config can be extended by `child` configs that override specific fields. Implement a system that (1) loads and merges configs (child overrides base), (2) validates required fields and value types, and (3) detects circular inheritance. ```python class ConfigLoader: def load(self, config_id: str, all_configs: dict) -> dict: """ all_configs = {id: {"extends": str|None, "fields": dict}} Returns merged, validated config or raises on error. """ def validate(self, merged: dict, schema: dict) -> list[str]: """Returns list of validation error messages.""" ``` **Example:** ``` configs = { "base": {"extends": None, "fields": {"cpu": 4, "memory_gb": 16}}, "gpu_worker": {"extends": "base", "fields": {"memory_gb": 64, "gpu": "A100"}} } loader.load("gpu_worker", configs) # -> {"cpu": 4, "memory_gb": 64, "gpu": "A100"} ``` ## Follow-ups 1. How do you detect circular inheritance? What data structure do you use? 2. What merge strategy handles list fields — replace the whole list or append? 3. How do you handle a child config referencing a non-existent base? 4. If configs are stored in a remote config service, how do you cache them safely?
Citadel SWE Phone - Minimum Talent Window (Sliding Window)
## Problem Find the minimum window in a sequence that contains all required talent or skill types. ## Likely LeetCode equivalent Same as LC 76 Minimum Window Substring. ## Tags sliding_window, citadel, strings
## Problem Implement a limit order book that maintains bids and asks sorted by price-time priority. Support: add order, cancel order, and market order execution. After every operation, report the best bid and best offer (BBO). All operations must be O(log n) or better. ```python class LimitOrderBook: def add_limit(self, order_id: str, side: str, price: float, qty: int) -> dict: ... def cancel(self, order_id: str) -> bool: ... def execute_market(self, side: str, qty: int) -> list[dict]: ... def bbo(self) -> dict: # {best_bid: float, best_ask: float} ``` **Example:** ``` add_limit("L1", "buy", 99.5, 100) -> bbo: {best_bid: 99.5, best_ask: None} add_limit("L2", "sell",100.0, 50) -> bbo: {best_bid: 99.5, best_ask: 100.0} execute_market("buy", 50) -> [{fill: L2, price:100.0, qty:50}] bbo() -> {best_bid: 99.5, best_ask: None} ``` ## Follow-ups 1. What data structure gives you O(log n) add/cancel and O(1) best-price? Describe the two-level structure. 2. How do you handle multiple orders at the same price level (price queue vs. sorted set)? 3. At 1M order operations/sec, what are the bottlenecks in a single-threaded Python implementation? 4. How would you persist the order book state so it survives a crash mid-session?
## Problem You receive a stream of `(symbol, price, timestamp)` ticks. Implement a `PriceChangeDetector` that: (1) tracks the running VWAP (volume-weighted average price) per symbol, (2) fires an alert if a new price deviates more than X% from the VWAP, and (3) returns the percentage change from the previous tick. ```python class PriceChangeDetector: def __init__(self, alert_threshold_pct: float): ... def tick(self, symbol: str, price: float, volume: int, timestamp: int) -> dict: """ Returns { "pct_change_from_prev": float, "vwap": float, "alert": bool } """ ``` **Example:** ``` d = PriceChangeDetector(alert_threshold_pct=5.0) d.tick("AAPL", 150.0, 1000, 1) -> {pct_change: None, vwap: 150.0, alert: False} d.tick("AAPL", 160.0, 500, 2) -> {pct_change: 6.67, vwap: 153.3, alert: True} ``` ## Follow-ups 1. How do you compute VWAP incrementally without storing all historical ticks? 2. If you want a rolling VWAP over only the last N minutes, how does the calculation change? 3. How would you handle the case where the same symbol arrives from multiple exchanges simultaneously? 4. Design a simple alerting pipeline: how do alerts flow from detection to a trader's dashboard?
## Problem Given an `m x n` matrix of integers sorted in ascending order both row-wise and column-wise, implement three operations: (1) search for a target in O(m+n), (2) rotate the matrix 90 degrees clockwise in-place (for square matrices), and (3) return all elements in spiral order. ```python def search_matrix(matrix: list[list[int]], target: int) -> tuple[int, int] | None: # Start top-right; move left if too big, down if too small pass def rotate_90(matrix: list[list[int]]) -> None: # In-place for square matrix pass def spiral_order(matrix: list[list[int]]) -> list[int]: pass ``` **Example (search):** ``` matrix = [[1,4,7],[2,5,8],[3,6,9]], target=5 Output: (1, 1) spiral_order([[1,2,3],[4,5,6],[7,8,9]]) -> [1,2,3,6,9,8,7,4,5] ``` ## Follow-ups 1. Why does starting from the top-right corner give O(m+n) for search? 2. For in-place 90-degree rotation: what is the two-step approach (transpose then reverse)? 3. Extend spiral_order to work on non-square (rectangular) matrices. 4. How would you find the kth smallest element in a row-and-column sorted matrix?
Reject Rate Alert: Monitor Service Reject Rate and Trigger Alerts on Threshold Breaches
## Problem A service logs each request as either `accepted` or `rejected`. Implement a `RejectRateMonitor` that tracks the reject rate over a sliding window of the last `W` seconds and fires an alert when the rate exceeds a threshold `T` for `C` consecutive evaluation intervals. ```python class RejectRateMonitor: def __init__(self, window_sec: int, threshold: float, consecutive: int): ... def record(self, timestamp: int, outcome: str) -> bool: """ outcome: 'accepted' or 'rejected' Returns True if an alert should fire. """ def current_rate(self, timestamp: int) -> float: ... ``` **Example:** ``` m = RejectRateMonitor(window_sec=60, threshold=0.2, consecutive=3) # Feed 100 events with 25% reject rate for 3 minutes... m.record(180, "rejected") -> True # alert fires ``` ## Follow-ups 1. How do you implement the sliding window efficiently — deque vs. circular buffer vs. bucketed counts? 2. What happens if events arrive out of order within the window? How do you handle late arrivals? 3. How do you reset the consecutive counter when the rate drops below the threshold? 4. If you have 10,000 services each with their own monitor, how do you centralize alerting without per-service polling?
## Problem Simulate geological rock layer stacking or settling, processing layers in a specified order. ## Likely LeetCode equivalent No confident LC match. ## Tags arrays, simulation, citadel
Stock Exposure: Compute Portfolio Exposure to Individual Stocks Across Funds and Derivatives
## Problem A portfolio holds positions in individual stocks, ETFs (which have underlying stock weights), and options. Compute the net exposure to each underlying stock. An ETF position contributes its market value multiplied by each constituent's weight. An option contributes delta * notional to the underlying stock exposure. ```python def compute_exposure( positions: list[dict], # {symbol, qty, market_value, type} etf_compositions: dict, # {etf_symbol: {stock: weight}} option_deltas: dict # {option_symbol: {underlying, delta, notional}} ) -> dict: # {stock_symbol: net_exposure} pass ``` **Example:** ``` positions = [{symbol:"SPY", qty:10, market_value:5000, type:"etf"}, {symbol:"AAPL_CALL", qty:5, market_value:300, type:"option"}] etf_compositions = {"SPY": {"AAPL": 0.07, "MSFT": 0.06, ...}} option_deltas = {"AAPL_CALL": {"underlying":"AAPL", "delta":0.6, "notional":150}} Output: {"AAPL": 350 + 450, "MSFT": 300, ...} ``` ## Follow-ups 1. How do you handle ETFs that hold other ETFs (nested funds)? What is the termination condition? 2. If option delta changes with market conditions (gamma), how do you mark exposure in real time? 3. How would you present this as a risk report grouped by sector? 4. What precision/rounding strategy do you use to avoid floating-point drift across thousands of positions?
## Problem Reconstruct a target string from a set of fragments or word pieces. ## Likely LeetCode equivalent Similar to LC 139 Word Break. ## Tags strings, dynamic_programming, citadel
See All 18 Questions from This Round
Full question text, answer context, and frequency data for subscribers.
Get Access