← Citadel Interview Insights

Citadel·Software Engineer·Onsite - Coding / Algorithms·Senior

SeniorPrefer not to say
Jun 2026

Summary

Citadel coding round, one question, LFU cache from scratch. Pretty brutal if you haven't thought about frequency bucketing before.

Questions Asked (1)

Q1

Design and implement an LFU cache with get and put operations, both running in O(1) average time. On eviction, remove the least frequently used entry, breaking ties by recency.

Algorithms & Data StructuresSystem Design
Author's notes

The O(1) constraint is what makes this annoying.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Design an LFU cache using a combination of a hash map for O(1) key lookup and a frequency-based doubly linked list structure to track usage. Each frequency bucket contains a doubly linked list of nodes (keys) in recency order, and a min_freq pointer tracks the lowest frequency for O(1) eviction. Implement get and put by updating node frequencies and moving nodes between buckets in constant time.

Pro tip: Emphasize that the design achieves O(1) by using a min_freq pointer and that tie-breaking by recency is naturally handled by maintaining order within each frequency list. Also, mention edge cases like updating an existing key and handling capacity constraints.

1. Clarify requirements and constraints

Confirm that both get and put must be O(1) average time, and that eviction removes the least frequently used entry, with ties broken by least recently used. Discuss assumptions like positive capacity and integer keys/values.

2. Design core data structures

Use a hash map (key -> node) for O(1) access. Maintain a doubly linked list of frequency buckets, each containing a doubly linked list of nodes with that frequency, ordered by recency. Track min_freq for O(1) eviction.

3. Define node and bucket structures

Each node stores key, value, frequency, and pointers to prev/next in its frequency list. Each frequency bucket stores its frequency value and pointers to the head/tail of its node list, plus prev/next bucket pointers.

4. Implement get and put operations

For get: if key exists, increment its frequency, move it to the appropriate bucket (creating if needed), update min_freq if necessary, and return value. For put: if key exists, update value and increment frequency; else, if at capacity, evict from min_freq bucket's tail (LRU), then insert new node with frequency 1.

5. Analyze complexity and edge cases

Argue that all operations are O(1) average due to hash map lookups and constant-time list manipulations. Discuss edge cases: capacity 0, updating existing key, and when min_freq bucket becomes empty.

Key Points to Mention

  • Use of a hash map for O(1) key lookup and a frequency-based doubly linked list structure.
  • Maintaining a min_freq pointer to achieve O(1) eviction.
  • Tie-breaking by recency: within each frequency bucket, nodes are ordered from most to least recently used.
  • Handling frequency updates: moving nodes between buckets and creating/removing buckets as needed.
  • Edge cases: capacity 0, updating an existing key, and eviction when multiple nodes have the same frequency.
  • Complexity analysis: O(1) average time for both get and put, with O(capacity) space.

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