2073. Time Needed to Buy Tickets - Explanation
Description
There are n people in a line queuing to buy tickets, where the 0-th person is at the front of the line and the (n - 1)-th person is at the back of the line.
You are given a 0-indexed integer array tickets of length n where the number of tickets that the i-th person would like to buy is tickets[i].
Each person takes exactly 1 second to buy a ticket. A person can only buy 1 ticket at a time and has to go back to the end of the line (which happens instantaneously) in order to buy more tickets. If a person does not have any tickets left to buy, the person will leave the line.
Return the time taken for the person initially at position k (0-indexed) to finish buying tickets.
Example 1:
Input: tickets = [2,3,2], k = 2
Output: 6Explanation:
- The queue starts as [2,3,2], where the kth person is underlined.
- After the person at the front has bought a ticket, the queue becomes [3,2,1] at 1 second.
- Continuing this process, the queue becomes [2,1,2] at 2 seconds.
- Continuing this process, the queue becomes [1,2,1] at 3 seconds.
- Continuing this process, the queue becomes [2,1] at 4 seconds. Note: the person at the front left the queue.
- Continuing this process, the queue becomes [1,1] at 5 seconds.
- Continuing this process, the queue becomes [1] at 6 seconds. The kth person has bought all their tickets, so return 6.
Example 2:
Input: tickets = [5,1,1,1], k = 0
Output: 8Explanation:
- The queue starts as [5,1,1,1], where the kth person is underlined.
- After the person at the front has bought a ticket, the queue becomes [1,1,1,4] at 1 second.
- Continuing this process for 3 seconds, the queue becomes [4] at 4 seconds.
- Continuing this process for 4 seconds, the queue becomes [] at 8 seconds. The kth person has bought all their tickets, so return 8.
Constraints:
n == tickets.length1 <= n <= 1001 <= tickets[i] <= 1000 <= k < n
Topics
Prerequisites
Before attempting this problem, you should be comfortable with:
- Queue data structure - Simulating the ticket line with FIFO behavior
- Array iteration - Processing elements in circular order using modulo arithmetic
- Mathematical reasoning - The optimal solution calculates contributions directly without simulation
1. Queue
Intuition
We can simulate the ticket buying process exactly as described. People stand in a queue, and each person buys one ticket at a time before going to the back of the line. We continue this process until the person at position k has bought all their tickets.
Using a queue data structure naturally models this behavior. We track each person's index and decrement their remaining tickets each time they reach the front. When someone finishes buying all their tickets, they leave the queue. The simulation ends when the person at index k completes their purchase.
Algorithm
- Initialize a queue with indices
0ton-1representing each person's position. - Track the total time elapsed starting at
0. - While the queue is not empty, dequeue the front person and increment
timeby1. - Decrement that person's ticket count in the array.
- If their count reaches
0and their index equalsk, return the currenttime. - If their count is still positive, add them back to the queue.
class Solution:
def timeRequiredToBuy(self, tickets: List[int], k: int) -> int:
n = len(tickets)
q = deque()
for i in range(n):
q.append(i)
time = 0
while q:
time += 1
cur = q.popleft()
tickets[cur] -= 1
if tickets[cur] == 0:
if cur == k:
return time
else:
q.append(cur)
return timeTime & Space Complexity
- Time complexity:
- Space complexity:
Where is the size of the input array and is the maximum value in the input array.
2. Iteration
Intuition
Instead of using a queue, we can simulate the process by iterating through the array in a circular manner. We keep a pointer that cycles through positions 0, 1, 2, ..., n-1, 0, 1, ... and skip anyone who has already finished buying tickets.
This approach eliminates the need for a separate queue data structure while achieving the same simulation. We track time and decrement ticket counts as we cycle through, stopping when the person at position k finishes.
Algorithm
- Initialize an index pointer at
0and time counter at0. - Loop indefinitely, incrementing
timeand decrementing the current person's ticket count. - If the current person finishes (count becomes
0) and their index equalsk, returntime. - Move the index to the next position using modulo:
idx = (idx + 1) % n. - Skip over any person with zero tickets by advancing the index.
class Solution:
def timeRequiredToBuy(self, tickets: List[int], k: int) -> int:
n = len(tickets)
idx = 0
time = 0
while True:
time += 1
tickets[idx] -= 1
if tickets[idx] == 0:
if idx == k:
return time
idx = (idx + 1) % n
while tickets[idx] == 0:
idx = (idx + 1) % n
return timeTime & Space Complexity
- Time complexity:
- Space complexity:
Where is the size of the input array and is the maximum value in the input array.
3. Iteration (One Pass)
Intuition
Instead of simulating the entire process, we can calculate the answer directly. Consider how many times each person will buy a ticket before person k finishes.
For people standing at or before position k, they will buy tickets at most tickets[k] times, since they get to buy before person k in each round. For people standing after position k, they will buy at most tickets[k] - 1 times, since in the final round, person k finishes before they get another turn. Each person's contribution is capped by their own ticket needs.
Algorithm
- Initialize
resto0. - Iterate through each person from index
0ton-1. - For person at index
i <= k, addmin(tickets[i], tickets[k])to the result. - For person at index
i > k, addmin(tickets[i], tickets[k] - 1)to the result. - Return the total sum.
Time & Space Complexity
- Time complexity:
- Space complexity:
Common Pitfalls
Using the Wrong Bound for People After Position k
For people standing after position k, they only get tickets[k] - 1 turns before person k finishes (since person k completes on their final turn before these people get another chance). A common mistake is using tickets[k] for everyone, which overcounts the time contribution from people behind position k.
Confusing Position Index With Ticket Count
When calculating contributions, you must use min(tickets[i], tickets[k]) for i <= k and min(tickets[i], tickets[k] - 1) for i > k. Some solutions incorrectly compare indices instead of ticket counts, or forget to take the minimum, leading to counting more tickets than a person actually needs to buy.
Sign in to join the discussion