1599. Maximum Profit of Operating a Centennial Wheel
Problem Description
You operate a Ferris wheel (Centennial Wheel) with 4 gondolas, where each gondola can hold up to 4 people. The wheel rotates counterclockwise, and each rotation costs you runningCost
dollars.
You're given an array customers
where customers[i]
represents the number of new customers arriving just before the i
-th rotation (0-indexed). This means the wheel must rotate i
times before these customers arrive.
Key rules:
- You cannot make customers wait if there's room in a gondola
- Each customer pays
boardingCost
dollars when boarding the gondola at the ground level - Customers exit when their gondola returns to the ground (after a full rotation)
- At most 4 customers can board per rotation (even if more are waiting)
- Excess customers wait for the next rotation
- You can stop the wheel at any time, even before serving all customers
- Once you stop charging customers, all remaining rotations to safely unload passengers are free
Your goal is to find the minimum number of rotations that maximizes your profit. Profit is calculated as:
(total boarding fees collected) - (total running costs for paid rotations)
Return the optimal number of rotations, or -1
if no positive profit is possible.
Example scenario: If 5 customers arrive before rotation 0, only 4 can board immediately, and 1 must wait for the next rotation. You earn 4 * boardingCost
but pay runningCost
for that rotation.
Intuition
The key insight is that we need to simulate the actual operation of the Ferris wheel rotation by rotation, because the profit changes dynamically with each rotation and we want to find the optimal stopping point.
Think about it this way: at each rotation, we have some customers waiting (from previous arrivals or overflow), and potentially new customers arriving. We can board at most 4 people per rotation. Each rotation adds boardingCost * (number of people boarding)
to our revenue but costs us runningCost
to operate.
The profit at any point is cumulative - it's the total revenue minus total costs up to that rotation. Since we can stop at any time, we want to track the maximum profit we've seen so far and remember at which rotation it occurred.
Why can't we use a formula or mathematical approach? Because the arrival pattern is irregular - customers arrive in batches at specific rotations, and we have the constraint of maximum 4 people per gondola. This creates a queue of waiting customers that varies over time.
The simulation continues as long as either:
- We still have customers in the input array who haven't arrived yet, OR
- We have customers waiting to board
For each rotation, we:
- Add newly arriving customers to our waiting queue
- Board up to 4 customers (
up = min(wait, 4)
) - Calculate the profit change:
up * boardingCost - runningCost
- Track if this gives us a better total profit than before
The reason we track the "minimum number of rotations" for maximum profit is that if the same maximum profit occurs at different rotations, we want the earliest one (fewer rotations = stop earlier).
Solution Approach
The solution uses a simulation approach to track the Ferris wheel operation rotation by rotation.
Variables used:
ans = -1
: Stores the optimal number of rotations (initialized to -1 for the case when no positive profit is possible)mx = 0
: Tracks the maximum profit seen so fart = 0
: Current cumulative profitwait = 0
: Number of customers currently waiting to boardi = 0
: Current rotation number (counter)
Algorithm steps:
-
Continue simulation while needed: The loop runs as long as
wait > 0
(customers still waiting) ORi < len(customers)
(more customers will arrive). -
Handle new arrivals:
wait += customers[i] if i < len(customers) else 0
If we haven't processed all customer arrivals yet, add the new arrivals to the waiting queue.
-
Board customers:
up = wait if wait < 4 else 4 wait -= up
Board up to 4 customers from the waiting queue. If less than 4 are waiting, board them all.
-
Update profit:
t += up * boardingCost - runningCost
Add revenue from boarded customers and subtract the cost of this rotation.
-
Track maximum profit:
i += 1 if t > mx: mx = t ans = i
Increment rotation counter. If current profit exceeds the maximum seen so far, update both the maximum profit and the optimal number of rotations.
-
Return result: After simulation completes, return
ans
. If profit never became positive,ans
remains -1.
The beauty of this approach is its simplicity - it directly models the problem statement without trying to find a closed-form formula. By checking the profit at each rotation, we automatically find the optimal stopping point that maximizes profit.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example where customers = [8, 3]
, boardingCost = 5
, and runningCost = 6
.
Initial state:
ans = -1
(no profitable rotation found yet)mx = 0
(maximum profit so far)t = 0
(current cumulative profit)wait = 0
(customers waiting)i = 0
(rotation counter)
Rotation 0 (i=0):
- New arrivals:
wait = 0 + 8 = 8
(8 customers arrive) - Board customers:
up = min(8, 4) = 4
(only 4 can board) - Update waiting:
wait = 8 - 4 = 4
(4 customers still waiting) - Calculate profit:
t = 0 + (4 × 5) - 6 = 20 - 6 = 14
- Increment rotation:
i = 1
- Check if best:
14 > 0
, somx = 14
,ans = 1
Rotation 1 (i=1):
- New arrivals:
wait = 4 + 3 = 7
(3 more customers arrive, plus 4 waiting) - Board customers:
up = min(7, 4) = 4
- Update waiting:
wait = 7 - 4 = 3
- Calculate profit:
t = 14 + (4 × 5) - 6 = 14 + 20 - 6 = 28
- Increment rotation:
i = 2
- Check if best:
28 > 14
, somx = 28
,ans = 2
Rotation 2 (i=2):
- New arrivals:
wait = 3 + 0 = 3
(no new customers, i >= len(customers)) - Board customers:
up = min(3, 4) = 3
- Update waiting:
wait = 3 - 3 = 0
- Calculate profit:
t = 28 + (3 × 5) - 6 = 28 + 15 - 6 = 37
- Increment rotation:
i = 3
- Check if best:
37 > 28
, somx = 37
,ans = 3
End of simulation:
- No more waiting customers (
wait = 0
) and all arrivals processed (i >= len(customers)
) - Return
ans = 3
The optimal strategy is to run the Ferris wheel for 3 rotations, yielding a maximum profit of $37. Note how we had to continue past the point where all customers arrived (after rotation 1) because we still had waiting customers who could generate more profit.
Solution Implementation
1class Solution:
2 def minOperationsMaxProfit(
3 self, customers: List[int], boardingCost: int, runningCost: int
4 ) -> int:
5 # Initialize variables
6 min_rotations = -1 # Answer: minimum rotations for max profit (-1 if no profit)
7 max_profit = 0 # Track the maximum profit achieved
8 current_profit = 0 # Running total of profit
9 waiting_customers = 0 # Customers waiting in line
10 rotation = 0 # Current rotation number
11
12 # Continue while there are waiting customers or unprocessed customer groups
13 while waiting_customers > 0 or rotation < len(customers):
14 # Add new customers to the waiting line (if any arrive this rotation)
15 if rotation < len(customers):
16 waiting_customers += customers[rotation]
17
18 # Determine how many customers can board (max 4 per gondola)
19 customers_boarding = min(waiting_customers, 4)
20
21 # Update waiting customers after boarding
22 waiting_customers -= customers_boarding
23
24 # Calculate profit for this rotation
25 # Revenue from boarded customers minus cost of running the wheel
26 current_profit += customers_boarding * boardingCost - runningCost
27
28 # Move to next rotation
29 rotation += 1
30
31 # Update maximum profit and corresponding rotation number
32 if current_profit > max_profit:
33 max_profit = current_profit
34 min_rotations = rotation
35
36 return min_rotations
37
1class Solution {
2 public int minOperationsMaxProfit(int[] customers, int boardingCost, int runningCost) {
3 // Initialize result to -1 (no profitable rotation exists)
4 int optimalRotations = -1;
5
6 // Track maximum profit and current total profit
7 int maxProfit = 0;
8 int currentTotalProfit = 0;
9
10 // Track waiting customers and current rotation index
11 int waitingCustomers = 0;
12 int rotationIndex = 0;
13
14 // Continue rotating while there are waiting customers or new customers arriving
15 while (waitingCustomers > 0 || rotationIndex < customers.length) {
16 // Add new arriving customers to the waiting queue (if any)
17 if (rotationIndex < customers.length) {
18 waitingCustomers += customers[rotationIndex];
19 }
20
21 // Board up to 4 customers per rotation
22 int customersBoarding = Math.min(4, waitingCustomers);
23 waitingCustomers -= customersBoarding;
24
25 // Increment rotation count
26 rotationIndex++;
27
28 // Calculate profit for this rotation: (boarding revenue - operating cost)
29 currentTotalProfit += customersBoarding * boardingCost - runningCost;
30
31 // Update maximum profit and optimal rotation count if current profit is better
32 if (currentTotalProfit > maxProfit) {
33 maxProfit = currentTotalProfit;
34 optimalRotations = rotationIndex;
35 }
36 }
37
38 return optimalRotations;
39 }
40}
41
1class Solution {
2public:
3 int minOperationsMaxProfit(vector<int>& customers, int boardingCost, int runningCost) {
4 // Initialize variables to track the optimal number of rotations
5 int optimalRotations = -1; // Number of rotations for maximum profit (-1 if no profit)
6 int maxProfit = 0; // Maximum profit achieved so far
7 int currentProfit = 0; // Current accumulated profit
8
9 // Queue management variables
10 int waitingCustomers = 0; // Number of customers waiting in line
11 int rotationIndex = 0; // Current rotation number
12
13 // Continue rotating while there are waiting customers or new customers arriving
14 while (waitingCustomers > 0 || rotationIndex < customers.size()) {
15 // Add new customers to the waiting queue (if any arrive at this rotation)
16 if (rotationIndex < customers.size()) {
17 waitingCustomers += customers[rotationIndex];
18 }
19
20 // Board up to 4 customers on the gondola
21 int boardedCustomers = min(4, waitingCustomers);
22 waitingCustomers -= boardedCustomers;
23
24 // Move to next rotation
25 ++rotationIndex;
26
27 // Calculate profit for this rotation
28 // Profit = (boarded customers * boarding cost) - running cost
29 currentProfit += boardedCustomers * boardingCost - runningCost;
30
31 // Update maximum profit and optimal rotations if current profit is better
32 if (currentProfit > maxProfit) {
33 maxProfit = currentProfit;
34 optimalRotations = rotationIndex;
35 }
36 }
37
38 return optimalRotations;
39 }
40};
41
1/**
2 * Calculates the minimum number of rotations needed to achieve maximum profit for a Ferris wheel.
3 * @param customers - Array where customers[i] represents the number of customers arriving before the i-th rotation
4 * @param boardingCost - Profit earned per customer boarding
5 * @param runningCost - Cost per rotation of the wheel
6 * @returns The minimum number of rotations to achieve maximum profit, or -1 if profit cannot be positive
7 */
8function minOperationsMaxProfit(
9 customers: number[],
10 boardingCost: number,
11 runningCost: number,
12): number {
13 // Track the rotation number that yields maximum profit (-1 if no profit)
14 let optimalRotations: number = -1;
15
16 // Track the maximum profit achieved so far
17 let maxProfit: number = 0;
18
19 // Track the current total profit
20 let currentProfit: number = 0;
21
22 // Track the number of customers waiting in line
23 let waitingCustomers: number = 0;
24
25 // Track the current rotation index
26 let rotationIndex: number = 0;
27
28 // Continue rotating while there are waiting customers or new customers arriving
29 while (waitingCustomers > 0 || rotationIndex < customers.length) {
30 // Add new arriving customers to the waiting queue (if any)
31 if (rotationIndex < customers.length) {
32 waitingCustomers += customers[rotationIndex];
33 }
34
35 // Calculate how many customers can board (maximum 4 per rotation)
36 const customersToBoard: number = Math.min(4, waitingCustomers);
37
38 // Update the waiting queue after boarding
39 waitingCustomers -= customersToBoard;
40
41 // Increment rotation counter
42 rotationIndex++;
43
44 // Calculate profit for this rotation (boarding revenue minus operating cost)
45 currentProfit += customersToBoard * boardingCost - runningCost;
46
47 // Update maximum profit and optimal rotation count if current profit is better
48 if (currentProfit > maxProfit) {
49 maxProfit = currentProfit;
50 optimalRotations = rotationIndex;
51 }
52 }
53
54 return optimalRotations;
55}
56
Time and Space Complexity
The time complexity is O(n + m)
, where n
is the length of the customers
array and m
is the number of additional rotations needed to board all waiting customers after processing the array. In the worst case where each customer arrives one at a time and the wheel can only take 4 at once, m
could be proportional to the total number of customers, making the overall complexity O(total_customers)
. However, since we process the customers
array element by element and then continue until all waiting customers are boarded, the time complexity can be simplified to O(n)
when considering n
as representing the effective number of operations needed.
The space complexity is O(1)
as the algorithm only uses a constant amount of extra space regardless of the input size. The variables ans
, mx
, t
, wait
, i
, and up
are all scalar values that don't grow with the input size.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Stopping Too Early When Profit Becomes Negative
The Mistake: A common error is to stop the simulation as soon as the profit becomes negative or starts decreasing, thinking that's the optimal stopping point.
# INCORRECT approach - stops too early
while waiting_customers > 0 or rotation < len(customers):
# ... boarding logic ...
current_profit += customers_boarding * boardingCost - runningCost
rotation += 1
if current_profit <= 0: # Wrong! Stops at first negative
break
if current_profit > max_profit:
max_profit = current_profit
min_rotations = rotation
Why It's Wrong: The profit can temporarily dip negative but recover later when more customers arrive. For example:
- customers = [10, 10, 1, 0, 0], boardingCost = 4, runningCost = 20
- Early rotations might show negative profit, but accumulating customers leads to positive profit later
The Fix: Continue simulation through all possible rotations, tracking the maximum profit throughout:
# CORRECT approach - checks all possibilities
while waiting_customers > 0 or rotation < len(customers):
# ... boarding logic ...
current_profit += customers_boarding * boardingCost - runningCost
rotation += 1
# Always check if this is a new maximum, don't break early
if current_profit > max_profit:
max_profit = current_profit
min_rotations = rotation
Pitfall 2: Incorrectly Handling Empty Rotations
The Mistake: Not properly accounting for rotations where no customers board (either because none are waiting or none have arrived yet).
# INCORRECT - skips empty rotations
if waiting_customers > 0: # Wrong! Still costs money to rotate
customers_boarding = min(waiting_customers, 4)
current_profit += customers_boarding * boardingCost - runningCost
rotation += 1
Why It's Wrong: Even if no customers board, you still pay runningCost
for that rotation if you continue operating. This affects the total profit calculation.
The Fix: Always account for the running cost when the wheel rotates, regardless of whether customers board:
# CORRECT - accounts for all rotations
customers_boarding = min(waiting_customers, 4) # Could be 0
current_profit += customers_boarding * boardingCost - runningCost # Always subtract runningCost
rotation += 1
Pitfall 3: Off-by-One Error in Rotation Counting
The Mistake: Confusing when to increment the rotation counter - before or after updating the maximum profit.
# INCORRECT - updates rotation before checking profit
while waiting_customers > 0 or rotation < len(customers):
rotation += 1 # Wrong position!
# ... boarding logic ...
current_profit += customers_boarding * boardingCost - runningCost
if current_profit > max_profit:
max_profit = current_profit
min_rotations = rotation # This is now off by one
Why It's Wrong: This makes the rotation count represent the "next" rotation rather than the "just completed" rotation, leading to incorrect answers.
The Fix: Increment rotation after calculating profit but before checking for maximum:
# CORRECT - proper ordering
while waiting_customers > 0 or rotation < len(customers):
# ... boarding logic ...
current_profit += customers_boarding * boardingCost - runningCost
rotation += 1 # Increment after profit calculation
if current_profit > max_profit:
max_profit = current_profit
min_rotations = rotation # Now correctly represents completed rotations
Consider the classic dynamic programming of fibonacci numbers, what is the recurrence relation?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!