How to Pass the Zepto SDE-2 LLD Interview

Zepto's engineering culture moves incredibly fast. Their SDE-2 Low-Level Design (LLD) interviews reflect that exact intensity. You aren't just building standard CRUD applications here; they expect you to handle complex operational logic, high concurrency, and optimal data structures. One of the most notorious questions in their LLD battery is the train ticket booking engine. There's a catch, though: you have to implement segment-based seat reusability. If a passenger books a seat from station A to station B, that exact seat needs to immediately become available for another passenger traveling from station B to station C. Pulling this off requires a rock-solid understanding of database schema design, algorithmic efficiency, and concurrency control.
The Zepto SDE-2 Interview Process
Let's look at where this specific question fits into the broader Zepto interview loop before we jump into the technical solution. The SDE-2 process typically consists of four main rounds. These sessions heavily index on your ability to write clean, concurrent, and scalable code under pressure.
| Round | Focus Area | Duration |
|---|---|---|
| 1. DSA & Problem Solving | Medium/Hard LeetCode, Trees, Graphs, DP | 60 mins |
| 2. Machine Coding / LLD | Concurrency, OOD, Design Patterns (The Train Problem) | 90-120 mins |
| 3. System Design (HLD) | Scalability, Microservices, DB Choice | 60 mins |
| 4. Hiring Manager | Behavioral, Past Projects, Culture Fit | 45 mins |
The Problem Statement: Train Booking with Seat Reusability
The core requirement of this LLD round is building a system where a single train journey gets broken down into segments. Imagine a train traveling through multiple stations (e.g., Station 1 to Station 10). Users can search for available seats between any two stations along the route. If Seat 42 is booked from Station 2 to Station 5, it should still show up as available for a search from Station 5 to Station 8. However, it must be unavailable for a search from Station 3 to Station 6. Your job is to design the models, the availability algorithm, and the concurrency strategy to completely prevent double-booking.
How do you design the database schema for stations, segments, and seat bookings?
A very common mistake candidates make here is creating a row for every single station-to-station combination for every seat. Think about the math. With 50 stations, that's nearly 1,225 combinations per seat. Multiply that by 1,000 seats, and your database grows unnecessarily massive for just one single train journey. Instead, we need to model the journey as sequential segments.
- Train: train_id, name, total_seats
- Station: station_id, name
- Route: route_id, train_id
- RouteStation: route_id, station_id, stop_sequence (integer dictating the order)
- Seat: seat_id, train_id, coach_number, seat_number
- Booking: booking_id, user_id, train_id, source_station_id, dest_station_id, status
The real magic happens in how we store availability. Rather than storing combinations, we store the state of the seat across the entire route. This brings us straight to the algorithmic core of the interview.
How do you implement segment-based seat reusability efficiently?
The most elegant, high-performance way to solve the seat reusability problem is by using a Bitmask. Think of the train route as an array of segments. If a train has 5 stations (A, B, C, D, E), it effectively has 4 segments: A-B (bit 0), B-C (bit 1), C-D (bit 2), and D-E (bit 3). Because of this, we can represent the availability of any seat as a simple integer.

Initially, a seat's availability mask sits at 0000 (meaning all segments are free). If a user books a ticket from B to D, they're occupying segment 1 (B-C) and segment 2 (C-D). The required mask for this specific journey is 0110. To check if a seat is actually available, we just perform a bitwise AND operation between the seat's current mask and the requested mask. If (current_mask & requested_mask) == 0, the seat is good to go. We then update the seat's status using a bitwise OR: new_mask = current_mask | requested_mask.
How do you handle high concurrency and prevent double bookings?
In a real-world scenario like IRCTC or Zepto's high-traffic flash sales, hundreds of users might try to book the exact same overlapping segments simultaneously. If you simply read the availability, verify the bitmask, and then write the new bitmask, your system is highly vulnerable to race conditions.
You basically have two primary options to discuss with your interviewer here. The first is Pessimistic Locking using 'SELECT ... FOR UPDATE'. When a user selects a seat, you lock that specific row in the database until the transaction fully commits. This guarantees consistency, but it severely degrades throughput since concurrent transactions on the same seat end up blocked.
The better approach for this particular LLD is Optimistic Locking. You add a 'version' column to your SeatAvailability table. When a user requests a booking, you read both the current mask and the version. When it's time to update, your query looks like this: 'UPDATE SeatAvailability SET mask = new_mask, version = version + 1 WHERE seat_id = X AND version = expected_version'. If another transaction modified the row first, the version won't match. The update returns 0 rows affected, and you can catch this failure to either prompt the user to select another seat or automatically retry the operation.
What does the object-oriented class design look like?
A strong LLD requires a clean separation of concerns. You absolutely want to avoid monolithic classes; use interfaces and managers instead. When you're in the machine coding round, try structuring your application with the following core components:
- SearchService: Exposes 'searchAvailableSeats(source, destination, date)'. It translates stations to segment masks and queries the inventory.
- InventoryManager: Handles the bitwise logic and database interactions. Exposes 'lockSeat()' and 'releaseSeat()'.
- BookingService: Orchestrates the flow. It calls InventoryManager to lock the seat, interfaces with the PaymentGateway, and confirms the booking.
- PricingStrategy: An interface allowing dynamic pricing. You can implement 'StandardPricing' or 'SurgePricing' based on the fill rate of the train.
How do you handle edge cases like cancellations and partial bookings?
Interviewers love throwing edge cases at you once your base design looks solid. For cancellations, you just reverse the bitmask logic. If a user cancels their B to D journey (mask 0110), you update the seat's current mask using a bitwise AND NOT: new_mask = current_mask & ~canceled_mask. This perfectly frees up only the specific segments the user had previously booked.
For partial bookings, imagine a family of 4 wants to sit together, but no single coach has 4 seats available for the entire journey. You'll want to discuss a grouping algorithm. The SearchService can look for contiguous seats first, then same-coach seats, and finally split seats across different coaches. Openly communicating these trade-offs—and acknowledging that finding contiguous seats is a much harder algorithmic problem (often requiring sliding window checks over the seat array)—really demonstrates senior-level product thinking to the hiring manager.
Ace Your Zepto Interview with AcePrompt
Designing a concurrent train booking system in under two hours is incredibly challenging. You have to balance database schema design, bitwise algorithms, and concurrency control, all while communicating clearly with your interviewer. Practicing these patterns is absolutely essential. Having real-time guidance during your mock interviews or actual rounds, however, can make all the difference.
AcePrompt AI acts as your real-time interview copilot. It listens to the technical constraints your interviewer introduces and provides structured, personalized hints directly on your screen. If you need a quick reminder on optimistic locking syntax or a nudge toward the bitmask approach for segment availability, AcePrompt ensures you never draw a blank.
Frequently asked questions
What is the focus of the Zepto SDE-2 LLD round?
The Zepto SDE-2 LLD round focuses heavily on concurrency, optimal data structures, and object-oriented design. They expect you to write clean, executable code during the machine coding segment that handles real-world operational complexities like race conditions and high throughput.
Why use a bitmask for seat availability instead of rows?
A bitmask lets you represent the availability of a seat across multiple route segments using just a single integer. This turns what would be complex relational database queries into a fast, O(1) bitwise operation. It saves massive amounts of storage while drastically improving read and write speeds.
How do you prevent two users from booking the same seat?
You prevent double bookings by using Optimistic Locking (adding a version number to the seat row and checking it on update) or Pessimistic Locking (using SELECT FOR UPDATE to lock the row). Optimistic locking is generally the preferred approach for ticketing systems because it maintains high read throughput.
Is machine coding done on a specific platform at Zepto?
Zepto typically allows candidates to use their preferred IDE for machine coding rounds. You'll usually share your screen, write the code locally on your own machine, and walk the interviewer through your class structure and execution flow.
Related comparisons
See AcePrompt in action
Watch how AcePrompt supports a real technical round - structured answers, tuned to your resume, in real time.
Never freeze in a system design interview again—try AcePrompt's real-time AI copilot today.
Get started