Tiered Expiring Item Store
Reported by candidates from Hudson River Trading's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
The mistake that sinks a first attempt on this Hudson River Trading OA, reported in September 2026, is purging expired items lazily in the wrong place. Tiered Expiring Item Store looks like a pile of rules, but it's a design and simulation problem built on heaps and hash maps. You've got an invite and a day or two. Read the state rules twice. STORE never purges, only RETRIEVE does, and that detail flips outputs in the examples. If you blank mid-assessment, StealthCoder runs invisibly as a safety net and reads the problem for you.
The problem
You manage a tiered item store whose levels are ordered from top to bottom. Level i has the fixed positive capacity levelCapacities[i]. Implement processTieredStore to process operations in order and return one string result for every operation. Operations STORE itemId weight expiresAt: If itemId is already stored, return "false". Otherwise, place the item in the first top-to-bottom level with a free slot and return "true". If every level is full, return "false". RETRIEVE now:Remove every stored item whose expiresAt is less than or equal to now. Scan the levels from top to bottom. A level is eligible when it is nonempty and its number of free slots is at least half of its capacity. Equivalently, 2 * freeSlots >= capacity. From the first eligible level, remove and return the ID of its heaviest live item. If several items have the same maximum weight, choose the lexicographically smallest ID. If no level is eligible, return "null". State Rules A STORE operation does not purge expired items because it has no current-time argument. An item ID remains unavailable while that item is stored, even if its expiration time has passed but no RETRIEVE operation has purged it. An ID may be stored again after its prior item is retrieved or purged as expired. Every operation contributes exactly one entry to the returned array. Function processTieredStore(levelCapacities: int[], operations: String[]) → String[] Examples Example 1 levelCapacities = [4,2] operations = ["STORE a 5 5","STORE b 9 5","STORE c 7 20","STORE d 6 20","STORE e 10 20","RETRIEVE 5","RETRIEVE 5","RETRIEVE 5"] return = ["true","true","true","true","true","c","d","e"] At time 5, items a and b expire. The top level then has two free slots out of four, so it is eligible exactly at the half-capacity boundary. It returns c, then d. Once that level is empty, the lower level returns e. Example 2 levelCapacities = [2] operations = ["STORE x 8 3","RETRIEVE 3","STORE x 4 10","RETRIEVE 9","STORE x 6 12","STORE x 7 15","RETRIEVE 12"] return = ["true","null","true","x","true","false","null"] The first x expires when now = 3, so retrieval returns "null" and the ID becomes reusable. The second x is live at time 9 and is retrieved. The next store succeeds, its active duplicate is rejected, and expiration at time 12 makes the final retrieval return "null". Example 3 levelCapacities = [4,2] operations = ["STORE alpha 8 30","STORE beta 8 30","STORE old1 1 5","STORE old2 1 5","STORE gamma 9 6","STORE delta 9 30","RETRIEVE 5","RETRIEVE 5","RETRIEVE 6"] return = ["true","true","true","true","true","true","alpha","beta","delta"] Purging old1 and old2 makes the top level eligible. Although the lower level holds heavier items, top-to-bottom level order wins first. The tie between alpha and beta is broken lexicographically. At time 6, gamma expires and the lower level returns delta. Constraints 1 <= levelCapacities.length <= 50 1 <= levelCapacities[i] <= 10^5 The sum of all level capacities is at most 2 * 10^5. 1 <= operations.length <= 2 * 10^5. Every operation has valid syntax and is either STORE itemId weight expiresAt or RETRIEVE now. Each itemId has length from 1 through 20 and contains only letters, digits, underscores, or hyphens. 1 <= weight, expiresAt, now <= 10^9.
Reported by candidates. Source: FastPrep
Pattern and pitfall
The trick is keeping each level's data structure fast for three queries: remove all expired, find the heaviest with a lexicographic tiebreak, and delete arbitrary items. Use a global min-heap keyed by expiresAt to purge, and per level a max-heap keyed by (weight desc, id asc) with lazy deletion. A hash map from itemId to its state tells you whether a heap entry is still live. The common pitfall is purging on STORE, or forgetting that an expired but unpurged ID still blocks a duplicate. Another is the eligibility test. Use 2 * freeSlots >= capacity with integers, and require the level to be nonempty. Track a live count per level, not heap size, since lazy entries inflate it. With 2 * 10^5 operations, a per-operation scan over 50 levels is fine, but rebuilding heaps isn't. If the design slips under pressure, StealthCoder is the hedge during the live OA.
Memorize the pattern. If you can't, run StealthCoder. The proctor sees the IDE. They don't see what's behind it.
You can drill Tiered Expiring Item Store 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. Made by an engineer who treats the OA as theater. If yours is tonight, you don't have time to grind. You have time to hedge.
Get StealthCoderRelated leaked OAs
You've seen the question.
Make sure you actually pass Hudson River Trading's OA.
Hudson River Trading reuses patterns across OAs. Made by an engineer who treats the OA as theater. If yours is tonight, you don't have time to grind. You have time to hedge. Works on HackerRank, CodeSignal, CoderPad, and Karat.
Tiered Expiring Item Store FAQ
What's the main trick in Tiered Expiring Item Store?+
Pair a global min-heap on expiresAt for purging with a per-level max-heap on weight, ties broken by smallest ID. Use lazy deletion and a hash map of live items so stale heap entries get skipped instead of removed in the middle.
Does STORE ever remove expired items?+
No. STORE has no current time, so it purges nothing. An expired item still blocks its ID and still occupies a slot until a RETRIEVE clears it. Example 2 shows this: a stale ID is only reusable after a RETRIEVE purges it.
How do I check if a level is eligible?+
Compute free slots as capacity minus live count, then test 2 * freeSlots >= capacity and live count above zero. Stay in integers to avoid float errors. Example 1 hits the exact half-capacity boundary, so use greater-than-or-equal.
How hard is this one really?+
Medium-hard on implementation, not on ideas. Nothing exotic is needed, but the rules are fiddly and the bookkeeping is easy to corrupt. Lazy deletion consistency across two kinds of heaps is where most attempts break.
How do I prepare in 48 hours?+
Hand-trace the three examples against your design, especially example 3, where level order beats weight. Write a small brute force and compare on random tests. Make sure you can code lazy-deletion heaps and a lexicographic tiebreak from memory.