← Ziprecruiter Interview Insights

Ziprecruiter·Software Engineer·Technical Phone Screen·Intermediate

Intermediate
Jun 2026

Summary

ZipRecruiter SWE interview centered on a system design coding problem that started simple and kept growing. The TTL extension was the real meat of it, and the discussion around expiration strategies went longer than I expected.

Questions Asked (3)

Q1

Design an in-memory key-value store where each key maps to a set of field-value pairs. Support operations like set, get, scan (returns all pairs sorted lexicographically by field), and scan by prefix.

System DesignAlgorithms & Data StructuresData Modeling
Author's notes

The base version wasn't too bad.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying requirements and constraints, then propose a data model using a hash map for keys and a balanced BST or sorted list for fields to support ordered scans. Discuss trade-offs between different data structures and outline how to implement each operation efficiently, including prefix scans.

Pro tip: Mention that you would use a concurrent data structure or locking strategy to handle concurrent access, and discuss how to optimize for memory usage and scan performance.

1. Clarify Requirements

Ask about expected scale, concurrency needs, persistence requirements, and whether fields are unique per key. Confirm that scan returns all field-value pairs sorted lexicographically by field, and scan by prefix returns only those with fields starting with a given prefix.

2. Design Data Model

Propose a two-level structure: a hash map from keys to a collection of field-value pairs. For the collection, consider a balanced binary search tree (e.g., red-black tree) or a sorted array/list to maintain fields in sorted order for efficient scans.

3. Implement Operations

For set: update or insert the field-value pair in the key's collection. For get: retrieve the value for a specific field. For scan: traverse the collection in order. For scan by prefix: use the sorted structure to find the starting point and iterate until the prefix no longer matches.

4. Analyze Complexity and Trade-offs

Discuss time and space complexity for each operation. Compare using a hash map vs. tree for fields, and consider alternatives like skip lists or trie for prefix scans. Mention memory overhead and potential optimizations.

5. Address Concurrency and Scalability

If needed, discuss thread-safety using locks (e.g., per-key locks) or concurrent data structures. Consider sharding or partitioning for scalability, and how to handle large datasets that exceed memory.

Key Points to Mention

  • Choice of data structures: hash map for keys, balanced BST or sorted list for fields to support ordered scans.
  • Time complexity: O(1) average for set/get, O(log n + k) for scan and prefix scan where k is number of results.
  • Prefix scan implementation: use the sorted structure to locate the first field >= prefix and iterate while fields start with prefix.
  • Concurrency: use read-write locks or concurrent hash maps, and consider lock striping for better performance.
  • Memory optimization: consider compact representations, such as storing fields in a trie for prefix scans, or using a B-tree for disk-based storage if needed.
  • Trade-offs: sorted array allows binary search but costly insertions; balanced BST offers O(log n) insertions and ordered traversal.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

Extend the key-value store to support TTL (time-to-live). Each operation now takes an explicit timestamp, and fields should expire a given number of time units after they're set. How do reads and writes behave when a field is expired or re-set?

System DesignTechnical Trade-offsData Modeling
Author's notes

This is where things got interesting and also where I fumbled a bit.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the data model and TTL semantics: each field has a value and an expiration timestamp (set time + TTL). For reads, check if the current timestamp is past the expiration; if so, treat the field as absent (and optionally lazily delete it). For writes, overwrite the value and reset the expiration timestamp based on the new TTL, ensuring atomicity and consistency.

Pro tip: Mention that using explicit timestamps makes the system deterministic and testable, and discuss trade-offs between lazy deletion (on read) and active expiration (background sweeper) to show depth.

1. Clarify requirements and data model

Confirm that each field stores a value and an expiration timestamp (set time + TTL). Ensure operations take an explicit timestamp for determinism.

2. Define read behavior for expired fields

On read, compare current timestamp with expiration. If expired, return 'not found' or null, and optionally delete the field lazily to free space.

3. Define write behavior for expired and re-set fields

On write, always overwrite the value and reset the expiration timestamp to current timestamp + TTL. If the field was expired, the write effectively revives it.

4. Address consistency and concurrency

Ensure operations are atomic: reads and writes should see a consistent view. Consider using locks or atomic operations to prevent races between expiration and access.

5. Discuss trade-offs and edge cases

Compare lazy vs. active expiration, handle TTL updates (e.g., KEEPTTL vs. reset), and consider clock skew and timestamp precision.

Key Points to Mention

  • Expiration timestamp = set time + TTL; store it alongside the value.
  • Reads on expired fields should behave as if the field does not exist (return null/not found).
  • Writes always overwrite and reset the TTL, even if the field was expired.
  • Lazy deletion on read vs. active background expiration: trade-offs in memory and CPU.
  • Atomicity: ensure that read-check-expire and write-reset-TTL are atomic to avoid race conditions.
  • Explicit timestamps make the system deterministic and easier to test; consider clock skew if using real time.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

Compare lazy expiration (skip expired fields on read) versus active background expiration. What are the trade-offs in terms of memory usage and latency?

Technical Trade-offsSystem Design
Author's notes

I actually felt okay here.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by defining both expiration strategies and their core mechanics. Then compare them across memory usage and latency, highlighting trade-offs and when each is preferable. Conclude with a practical recommendation based on workload characteristics.

Pro tip: Mention that many production systems use a hybrid approach: lazy expiration on read combined with periodic active sweeps, balancing memory and latency. This shows you understand real-world implementations beyond textbook definitions.

1. Define the strategies

Briefly explain lazy expiration (checking and removing expired items on access) and active expiration (background process periodically scanning and removing expired items).

2. Analyze memory usage

Discuss how lazy expiration can lead to memory bloat if expired items are not accessed, while active expiration proactively frees memory but may consume CPU and memory for the background process.

3. Analyze latency

Explain that lazy expiration adds latency to read operations (due to expiration checks and possible deletions), whereas active expiration can cause latency spikes during sweeps but keeps read latency predictable.

4. Consider workload and system constraints

Relate the trade-offs to specific scenarios: high read throughput, memory-constrained environments, or systems with many rarely accessed keys.

5. Recommend a hybrid or context-specific approach

Suggest that a combination of both (e.g., lazy on read plus periodic active sweeps) often works best, and tailor the recommendation to the given constraints.

Key Points to Mention

  • Lazy expiration avoids background CPU overhead but can cause memory leaks if expired items are never accessed.
  • Active expiration ensures timely memory reclamation but may introduce latency spikes and consume resources.
  • Read latency: lazy expiration adds per-access overhead; active expiration keeps reads fast but may cause periodic pauses.
  • Memory usage: lazy expiration may hold expired data indefinitely; active expiration bounds memory but requires tuning sweep frequency.
  • Hybrid approaches (e.g., Redis) combine lazy checks with periodic active sweeps to balance trade-offs.
  • Consider access patterns: if keys are frequently accessed, lazy expiration may suffice; if not, active expiration is safer.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.