Reported September 2026
Uberdesign

Per-Element Hit Counter

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

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

The constraint that kills brute force here is 10000 commands with a 300-second window. Rescanning every past hit on each GET or TOTAL turns into a quadratic mess. This Uber OA, reported in September 2026, is a per-element hit counter. Timestamps never go backward, and that's the whole gift. You can keep a queue of hits and expire old ones from the front as time moves forward. If you blank on the structure mid-assessment, StealthCoder runs invisibly on your desktop and hands you the working approach. Here's the shape of it before you ever need that.

The problem

Process a chronological batch of hit-counter commands. Each command is one of:
HIT el timestamp records one hit of element el at timestamp.
GET el timestamp returns how many hits of el fall in the half-open window (timestamp - 300, timestamp].
TOTAL timestamp returns how many hits of any element fall in that same window.
Timestamps are positive and non-decreasing. A hit at time t is counted by a query at time q if and only if q - 300 < t <= q.
Return the results of the GET and TOTAL commands in the order they appear.

Function
processHitCounterCommands(commands: String[]) → int[]

Examples
Example 1
commands = ["HIT a 1","HIT b 2","HIT a 2","GET a 2","GET b 2","TOTAL 2"]
return = [2,1,3]
At time 2, element a has hits at 1 and 2, element b has one hit, and the three hits together make the total 3.
Example 2
commands = ["HIT a 1","HIT a 2","HIT b 300","GET a 301","GET b 301","TOTAL 301"]
return = [1,1,2]
The query window at time 301 is (1, 301], so the hit of a at time 1 has expired. The remaining hits are a at 2 and b at 300.

Constraints
1 <= commands.length <= 10000.
Each command is exactly HIT el timestamp, GET el timestamp, or TOTAL timestamp.
Every el is a nonempty string of at most 16 lowercase English letters.
Timestamps are integers in [1, 10^9] and are non-decreasing across the batch.
At least one command is GET or TOTAL.

Reported by candidates. Source: FastPrep

Pattern and pitfall

The trick is that timestamps are non-decreasing, so expired hits only ever leave from the front. Keep one global deque of (timestamp) for TOTAL, and a map from element to its own deque for GET. On every query at time q, pop from the front while the stored timestamp is <= q - 300, then return the deque size. The pitfall is the boundary. The window is half-open, so a hit at exactly q - 300 is expired. Example 2 tests this: the hit at 1 is gone at 301. Another pitfall is only cleaning the deque you query, which is fine, but make sure the global deque gets cleaned on TOTAL too. Each hit is pushed and popped once, so it's O(n) overall. Since timestamps can reach 10^9, don't allocate an array by time. If you freeze during the live OA, StealthCoder is your hedge for the deque-and-map skeleton.

If you see this problem in your OA tomorrow, the play is to recognize the pattern in 30 seconds. StealthCoder buys you that recognition.

If this hits your live OA

You can drill Per-Element Hit Counter 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 by an Amazon engineer who passed his OA cold and still thinks the filter is broken.

Get StealthCoder

Related leaked OAs

⏵ Practice the LeetCode equivalent

This OA pattern shows up on LeetCode as design hit counter. If you have time before the OA, drill that.

⏵ The honest play

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

Uber reuses patterns across OAs. Built by an Amazon engineer who passed his OA cold and still thinks the filter is broken. Works on HackerRank, CodeSignal, CoderPad, and Karat.

Per-Element Hit Counter FAQ

What's the trick to the Uber per-element hit counter?+

Timestamps are non-decreasing, so old hits expire from the front only. Use a queue per element plus one global queue. On each query, pop entries with timestamp <= q - 300, then return the queue length. Every hit is added and removed once, so it's linear.

How hard is this problem really?+

Easy to medium. It's a design-style simulation with no tricky algorithm. Most people lose points on the half-open boundary or on cleaning stale hits incorrectly, not on the idea itself. If you've seen the classic hit counter, this is the same thing with a map.

Do I need a binary search instead of a queue?+

You could store timestamps in lists and binary search the window start, and that works too. But since queries are chronological, a queue with pop-from-front is simpler and avoids index bookkeeping. Binary search only matters if queries could arrive out of order, and they can't here.

What edge cases should I test before submitting?+

Test a hit at exactly q - 300, which should not count. Test a GET for an element that never got a hit, which should return 0. Test multiple hits at the same timestamp, and a TOTAL after everything expired. Example 2 covers the boundary, so run it first.

How do I prepare for this in 48 hours?+

Write the solution once from scratch with a map of deques and a global deque. Then trace both examples by hand, focusing on the window boundary. Practice a few other sliding-window-over-time problems so queue expiry feels automatic. That's enough for this one.

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

OA at Uber?
Invisible during screen share
Get it