Posting my DoorDash interview experience. My overall impression is that this company's questions are very tied to the business — almost every question comes wrapped in a food-delivery scenario, even when the core is just a template problem. The upside is it's not boring to talk through; the downside is you have to unwrap the packaging first and figure out what the core problem actually is — get that wrong and you've wasted your write-up.
Round 1: Coding
The interviewer opened by asking whether I order delivery food, then said, "then you should have a feel for this one."
The problem was dressed up like this: a courier has to finish delivering N orders within H hours. Each order has a "workload," the courier can only work on part of one order per hour, at a processing speed of K units per hour, and can't work on two orders in the same hour (even if they finish early, the rest of that hour is wasted). Find the minimum K.
Once you unwrap it, it's the classic Koko-eating-bananas binary search problem.
I restated the problem first to make sure I had it right, and specifically confirmed the rule that "if you can't finish within the hour, the rest of the time is wasted," since that's what makes each order's time round up. Once that was confirmed it was a standard binary search on the answer: K ranges from 1 to the max workload, and for each candidate K you compute the total time as sum(ceil(w / K)); if it fits within H hours, try a smaller K.
After I finished, he asked three follow-ups:
First, why the upper bound for K is the max workload rather than the sum. Because a larger K doesn't help — you can only finish at most one order per hour anyway.
Second, how to write the ceiling division without overflow or off-by-one errors. I used (w + K - 1) // K, and he had me explain why that's equivalent to ceiling division.
Third, what if the orders had priorities and had to be processed in a fixed order. I said it wouldn't matter, because the total time only depends on the sum of each order's time, not the order they're processed in. He agreed, then asked "what if there are multiple couriers?" That turns into a different class of problem — I said the approach would still be binary search on K, but the check function would need to become a greedy assignment: can you cover all the work with no more than M couriers. I ran out of time and only talked through the approach without coding it.
Round 2: Coding
The problem was dressed up as: orders come in one at a time, and at any point you need to be able to answer "among all current orders, which restaurant ID appeared exactly once first?"
Under the hood it's the classic "first unique number in a data stream" problem.
My design was a hash map plus a doubly linked list: the linked list only holds elements that are currently unique, in insertion order; the hash map maps each element to its linked-list node and also tracks how many times each element has appeared. On add, if it's the first occurrence, append it to the tail of the list and record the mapping; if it's the second occurrence, remove it from the list and set its mapping to a sentinel; from the third occurrence on, do nothing. showFirstUnique just returns the head of the list.
The interviewer followed up with a question I thought was pretty good: "does your hash map keep growing forever?" Yes — elements that have appeared twice stay in the map so you can detect a third occurrence. He asked if there was a way to reclaim that memory. I said if you can accept treating "appeared 3+ times" the same as "appeared 2 times," you can just keep a single "consumed" marker; if the total number of elements is very large, you'd need to think about sharding or eviction by time window.
The follow-up was concurrency: what happens if multiple threads call add at the same time. I said the simplest fix is a single big lock, but that would create serious contention. The improvement is to separate the linked-list operations from the counting: use a concurrent hash map for counting, and either fine-grained locks or a lock-free queue with lazy deletion for the list — meaning you let elements that are no longer unique stay in the list temporarily, and check and skip them when you read the head. He said that approach was right and that real systems do this a lot.
Round 3: Coding
This was the shortest problem of the round, but I wrote the messiest code for it.
The problem: given a string containing only parentheses, return the minimum number of characters you need to delete to make it valid.
For example, ")(" returns 2, ")(()())(" returns 2, and ")()" returns 1.
The core is a single pass: keep two counters. On an open paren, increment open. On a close paren, if open is greater than zero, cancel one out; otherwise it's an extra close paren, so increment the delete count. After the scan, whatever is left in open is the extra open parens, and the sum of the two is the answer.
I made a rookie mistake here: I started with a stack, and halfway through realized I wasn't actually using anything I pushed onto it — I was just counting. The interviewer prompted me with "do you actually need to remember which characters they were?" and that's when it clicked that two counters were enough, bringing the space down from O(n) to O(1).
The follow-up was to also return the positions to delete, which meant tracking indices — using a stack for the open-paren indices and another set for the close-paren indices to delete, then merging them at the end. I finished that one.
Lesson: don't reach for a stack the moment you see parentheses. Think first about what you actually need to remember.
Round 4: System Design
The problem: design a system that tracks and displays, in real time, the top 10 restaurants by order volume over the past hour.
The core of this one is event aggregation — the same pattern as the ad-click aggregation questions you see all over this forum.
My approach, in order:
Requirements clarification. How many orders per second, how much latency is acceptable (near-real-time or second-level), does it need to be exact or can it be approximate, is the time window tumbling or sliding, does it need to support looking back at history. The interviewer said second-level latency was fine, approximation was fine, and the window was a sliding one hour.
Data pipeline. The order service produces events, which get written to a message queue for buffering and decoupling; a stream-processing job consumes them and aggregates by restaurant ID; the results get written to storage; and a query service reads from that storage.
A few points got dug into:
First, how to implement the window. Recomputing a sliding one-hour window every second would be too expensive, so I said to bucket by minute — each bucket keeps a per-restaurant count for that minute, and at query time you merge the most recent 60 buckets. That way, adding a new minute only means adding one bucket and dropping one.
Second, hot restaurants. A handful of restaurants account for a large share of the traffic, so sharding by restaurant ID would overload a single shard. I said you can append a random suffix to the key for secondary sharding, then merge at aggregation time — the usual trick for spreading out a hot key.
Third, exact vs. approximate. Since approximation was fine, you could use something like a Count-Min Sketch to cut memory usage a lot, at the cost of some error. The interviewer reacted pretty positively to this and also asked whether the error would be an overestimate or an underestimate.
Fourth, out-of-order and duplicate events. Order events might arrive late or get resent. I said to attach a unique ID and event time to each event, make the consumer idempotent, and drop anything that arrives after a set threshold while logging a metric for it.
Fifth, fault tolerance. What happens if the streaming job crashes — I said you rely on checkpoint recovery, and the message queue retains data for a while so it can be replayed.
This round went pretty smoothly. With a few minutes left, we talked about "what if the product wants top 10 per user's city instead of a single global top 10" — I said that just changes the aggregation key from restaurant to city+restaurant, nothing fundamentally different.
Discussion
Loading comments…