Reported January 2021
Bloombergdesign

LFU Cache

Reported by candidates from Bloomberg's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.

Get StealthCoderRuns invisibly during the live Bloomberg OA. Under 2s to a working solution.
Founder's read

The edge case that kills a naive LFU Cache is updating an existing key when the cache is full. Bloomberg reported this one in January 2021, and it's a design problem with an O(1) requirement. Most people code the eviction path and forget that a put on an existing key must bump frequency and never evict. You're taking the OA soon, so know this before you start typing. The structure is a key map plus frequency buckets with ordered lists. If you blank under the clock, StealthCoder runs invisibly as a safety net and gives you the working solution while you keep your head.

The problem

Process commands on an initially empty least-frequently-used cache with positive integer capacity.
put key value inserts a new key or updates an existing key.
get key returns the stored value, or -1 when the key is absent.
For this exercise, assume a successful get and a put that updates an existing key each increase that key's frequency by one and make it most recently used within its new frequency. A new key starts with frequency one.
When a new insertion would exceed capacity, evict the key with the smallest frequency. Break a frequency tie by evicting the least recently used key. Return the results of all get commands in order. Each operation should run in average O(1) time.

Function
processLfuCache(capacity: int, operations: String[]) → int[]

Examples
Example 1
capacity = 2
operations = ["put 1 1","put 2 2","get 1","put 3 3","get 2","get 3","put 4 4","get 1","get 3","get 4"]
return = [1,-1,3,-1,3,4]
Reading key 1 raises its frequency, so key 2 is evicted first. Later keys 1 and 3 tie on frequency, and key 1 is least recent.
Example 2
capacity = 1
operations = ["put 7 5","put 7 8","get 7","put 9 4","get 7","get 9"]
return = [8,-1,4]
Updating key 7 changes its value and frequency. Inserting key 9 into a one-entry cache then evicts key 7.

Constraints
1 <= capacity <= 3000.
1 <= operations.length <= 2 * 10^4.
Each command is exactly get key or put key value.
Keys and values fit in signed 32-bit integers.
At least one command is get.

Reported by candidates. Source: FastPrep

Pattern and pitfall

The trick is two hash maps. One maps key to value and frequency. The other maps frequency to an ordered set of keys, oldest first, like a linked hash set. Track a minFreq variable. On every get or update, remove the key from its bucket, bump its frequency, and insert it into the next bucket at the most recent end. If the old bucket empties and it was minFreq, increment minFreq. On a new key at capacity, evict the oldest key in the minFreq bucket, then insert at frequency 1 and reset minFreq to 1. The pitfalls: evicting before checking whether the key already exists, forgetting that put on an existing key raises frequency, and forgetting to reset minFreq. Also collect only get results in the output array. If the data structure details slip during the live OA, StealthCoder is the hedge that gives you a clean implementation fast.

The honest play: practice the pattern, and have StealthCoder ready for the one you didn't see coming.

If this hits your live OA

You can drill LFU Cache cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. Built for the candidate who saw this exact problem leak two days before his OA and wondered if anyone had a play.

Get StealthCoder

Related leaked OAs

⏵ Practice the LeetCode equivalent

This OA pattern shows up on LeetCode as lfu cache. If you have time before the OA, drill that.

⏵ The honest play

You've seen the question. Make sure you actually pass Bloomberg's OA.

Bloomberg reuses patterns across OAs. Built for the candidate who saw this exact problem leak two days before his OA and wondered if anyone had a play. Works on HackerRank, CodeSignal, CoderPad, and Karat.

LFU Cache FAQ

How hard is the Bloomberg LFU Cache OA question really?+

It's hard on the design side, not the algorithm side. The idea is simple once you see it, but the bookkeeping is easy to get wrong. Expect to spend most of your time on frequency buckets and the minFreq update, not on complexity analysis.

What's the trick to getting O(1) for every operation?+

Keep a map from key to value and frequency, plus a map from frequency to an insertion-ordered set of keys. Track minFreq separately. Eviction pops the oldest key from the minFreq bucket, so nothing ever needs scanning or sorting.

What edge case breaks most solutions?+

A put on an existing key when the cache is full. It must update the value, bump the frequency, and not evict anything. Capacity 1 with repeated puts on the same key, like Example 2, tests exactly this.

Do I need a custom doubly linked list?+

Not necessarily. An insertion-ordered set per frequency gives you O(1) remove, add, and pop-oldest. In Java that's LinkedHashSet, in Python an OrderedDict. A hand-built doubly linked list works too but takes longer to write.

How do I prepare for this in 48 hours?+

Write the solution from scratch twice, then trace both examples by hand. Focus on when minFreq changes: reset to 1 on insert, increment when the minFreq bucket empties after a bump. Also practice parsing the operation strings into commands cleanly.

Problem reported by candidates from a real Online Assessment. Sourced from a publicly-available candidate-aggregated repository. Not affiliated with Bloomberg.

OA at Bloomberg?
Invisible during screen share
Get it