Quick Overview

Simulate buffet seating, FIFO waiting, early departures, and repeat visits while charging each guest at most once per day.

Compute Buffet Revenue with Waiting Guests and Repeat Visits

Company: Upstart

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Online Assessment

A buffet has a limited number of seats. Guests arrive, wait if necessary, eat if seated, and eventually leave. Each guest has a fixed amount they are willing to pay, but pays at most once during the entire day even if they visit more than once. Compute the day's total revenue. ### Function Contract Implement `compute_day_gains(nb_seats, paying_guests, guest_movements) -> int`. `paying_guests[g]` is the amount guest `g` pays on their first completed seated visit. Process `guest_movements` in order. Each occurrence of a guest identifier alternates between that guest arriving and departing: first arrival, then departure, then another arrival, and so on. Every arrival has a later matching departure, and a guest cannot have two active visits at once. ### Seating and Payment Rules - The restaurant starts empty. - An arrival takes a free seat immediately; otherwise the guest joins the waiting line. - For this exercise, the line is FIFO. When a seated guest departs, the longest-waiting guest still in line immediately takes the freed seat before the next movement is processed. - A departure by a waiting guest means that guest became bored and left without eating. It removes the guest from the line and does not free a seat. - A guest who departs after being seated pays their stated amount if they have not paid on an earlier visit that day. - A returning guest who already paid still requires a seat but never pays again. ### Constraints and Clarifications - `1 <= len(paying_guests) <= 10`. - `2 <= len(guest_movements) <= 26`. - Every movement is a valid guest identifier. - As explicit numeric practice bounds, `0 <= nb_seats <= 100` and each payment is an integer from `0` through `1000000`. - All visits are closed by the end of the movement sequence. - FIFO admission and immediate reuse of a freed seat make the waiting behavior deterministic. ### Examples ```text nb_seats = 1 paying_guests = [10, 20, 30] guest_movements = [0, 1, 2, 1, 0, 2] Output: 40 ``` Guest `1` leaves while waiting and pays nothing. Guest `0` pays 10 when leaving; guest `2` then takes the seat and later pays 30. ```text nb_seats = 1 paying_guests = [5] guest_movements = [0, 0, 0, 0] Output: 5 ``` The same guest completes two seated visits but pays only once. ```hint A visit state and a payment state are different A guest can be outside, waiting, or seated during a visit. Whether that guest has already paid must survive across later visits. ```

Overview: Simulate buffet seating, FIFO waiting, early departures, and repeat visits while charging each guest at most once per day.

A buffet has `nb_seats` seats and starts the day empty. `paying_guests[g]` is the amount guest `g` pays on their first completed seated visit; a guest pays at most once during the entire day, even if they visit more than once. Process `guest_movements` in order. Each occurrence of a guest identifier alternates between that guest arriving and that guest departing: the first occurrence of `g` is an arrival, the second is a departure, the third is another arrival, and so on. Every arrival has a later matching departure, and a guest cannot have two active visits at once. Seating and payment rules: - An arrival takes a free seat immediately; otherwise the guest joins the waiting line. - The waiting line is FIFO. When a seated guest departs, the longest-waiting guest still in line immediately takes the freed seat, before the next movement is processed. - A departure by a guest who is still waiting means that guest became bored and left without eating. It removes the guest from the line and does not free a seat. - A guest who departs after being seated pays `paying_guests[g]` if they have not paid on an earlier visit that day. - A returning guest who already paid still requires a seat but never pays again. Return the total amount collected during the day. The total can never exceed `10 * 1000000 = 10000000`, so it fits in a 32-bit integer; it is still returned as a 64-bit value (Java `long`, C++ `long long`). Example 1: ```text nb_seats = 1 paying_guests = [10, 20, 30] guest_movements = [0, 1, 2, 1, 0, 2] Output: 40 ``` Guest `0` takes the only seat, and guests `1` and `2` wait in that order. Guest `1` departs while waiting, so it pays nothing and frees no seat. Guest `0` then departs and pays 10, guest `2` immediately takes the freed seat and later departs and pays 30, for a total of 40. Example 2: ```text nb_seats = 1 paying_guests = [5] guest_movements = [0, 0, 0, 0] Output: 5 ``` The same guest completes two seated visits but pays only once, so the total is 5.

Constraints

  • 0 <= nb_seats <= 100
  • 1 <= len(paying_guests) <= 10
  • Each payment is an integer from 0 through 1000000
  • 2 <= len(guest_movements) <= 26
  • Every movement is a valid guest identifier: 0 <= guest_movements[i] < len(paying_guests)
  • Occurrences of a guest alternate arrival, departure, arrival, ...; a guest never has two active visits at once
  • All visits are closed by the end of the movement sequence
  • The returned total is at most 10 * 1000000 = 10000000

Examples

Input: (1, [7], [0, 0])

Expected Output: 7

Explanation: Minimum valid day: one guest takes the only seat and pays 7 on departure.

Input: (0, [10, 20], [0, 1, 1, 0])

Expected Output: 0

Explanation: With zero seats nobody is ever seated, so both departures are bored departures and nothing is paid.

Hints

  1. Each occurrence of a guest identifier flips that guest's visit state, so decide what a movement means from that guest's current state rather than from its position in the list.
  2. A guest's visit state (outside, waiting, seated) is a different thing from whether that guest has already paid today; the payment fact has to survive across later visits.
  3. A seat that opens up never stays open while someone is still in line - settle that handoff before you read the next movement.

Loading coding console...

Show the approach

Approach

Simulate the day one movement at a time, keeping four pieces of state: a counter of free seats, the set of guests currently seated, a FIFO queue of guests currently waiting, and the set of guests who have already paid today.

Because occurrences of a guest alternate arrival, departure, arrival, ... and a guest never has two active visits at once, the meaning of a movement is fully determined by that guest's current state: if the guest is seated, the movement is a departure from a seat; if the guest is in the line, it is a bored departure; otherwise it is an arrival.

Arrival: take a free seat if one exists, otherwise append to the back of the line. Seated departure: free the seat, collect paying_guests[g] if g is not yet in the paid set (and add it), then immediately pop the front of the line into the freed seat. Bored departure: remove that guest from the line and change nothing else - no seat is freed and nothing is paid.

Invariant: free_seats > 0 implies the waiting line is empty, because a released seat is handed to the longest-waiting guest in the same step, before the next movement is read. That invariant is exactly the source's determinism rule, and it is why an arrival only has to check free_seats and never the line.

Correctness: the paid set is keyed by guest rather than by visit, so a guest is counted exactly once no matter how many seated visits they complete, and never counted if they only ever waited; a payment of 0 still marks the guest as paid. Since all visits are closed by the end of the sequence, every completed seated visit is observed at its departure, so the accumulated total is exactly the day's revenue.

Edge cases: nb_seats = 0 means no one is ever seated, every departure is a bored departure and the answer is 0; a guest who got bored earlier may return, be seated, and pay then; guests listed in paying_guests who never appear in guest_movements contribute nothing; a repeat visit by an already-paid guest still consumes a seat but adds no revenue.

Time complexity:
O(m * g), where m = len(guest_movements) and g = len(paying_guests), since each movement does O(1) work plus at most one scan of a waiting line of length at most g
Space complexity:
O(g), for the seated set, the paid set, and the waiting line