The Number of Full Rounds You Have Played: Time Interval Math
Time-based problems feel tricky because you have to juggle string parsing, minute arithmetic, and boundary conditions all at once. This problem boils all of that down to one clean idea: convert to minutes, snap to 15-minute boundaries, and count the gap.
The problem
LeetCode 1904: The Number of Full Rounds You Have Played. You are given two strings loginTime and logoutTime in "HH:MM" format. A full round is any 15-minute interval that starts at HH:00, HH:15, HH:30, or HH:45. Count the number of full rounds you played during your session. A full round must start at or after login and end at or before logout. If logoutTime is earlier than loginTime, the session wraps past midnight into the next day.
The approach: snap to boundaries
The key insight is that you do not need to simulate each 15-minute block. Instead, you can reduce the problem to three arithmetic operations.
First, convert both times to total minutes since midnight. This turns "12:01" into 721 and "12:44" into 764, giving you plain integers to work with.
Second, handle the next-day wraparound. If the logout time in minutes is smaller than the login time, the session crosses midnight. Add 24 * 60 = 1440 to the logout value so the math stays correct.
Third, snap the boundaries. Round the login time up to the next 15-minute mark (the earliest a round can start). Round the logout time down to the previous 15-minute mark (the latest a round can end). The number of full rounds is just the gap between these two snapped values divided by 15, with a floor of zero in case the gap is negative.
This approach works because every full round aligns to one of the four quarter-hour marks in each hour. By snapping login forward and logout backward, you isolate exactly the window where complete rounds can fit.
Visual walkthrough
numberOfRounds("12:01", "12:44"):Step 1: Convert times to minutes
"12:01" => 12 * 60 + 1 = 721 minutes"12:44" => 12 * 60 + 44 = 764 minutesParse hours and minutes from each string, then compute total minutes since midnight.
Step 2: Handle next-day wraparound
764 >= 721, so no wraparound neededIf logout is earlier than login, the session crosses midnight. Add 1440 to the logout time. Here, logout > login, so no adjustment.
Step 3: Round login UP to next 15-minute boundary
721(721 + 14) // 15 * 15 = 735735 minutes = 12:15Login is at 12:01. The next 15-minute boundary is 12:15 (minute 735). You cannot start a round before this point.
Step 4: Round logout DOWN to previous 15-minute boundary
764764 // 15 * 15 = 750750 minutes = 12:30Logout is at 12:44. The previous 15-minute boundary is 12:30 (minute 750). A round must end at or before this point.
Step 5: Count full rounds
max(0, (750 - 735) // 15)max(0, 1) = 1One full 15-minute round fits: [12:15, 12:30). The round [12:30, 12:45) would end at 12:45, past the 12:44 logout. Answer: 1.
The only complete 15-minute interval within the session is [12:15, 12:30).
The code
def numberOfRounds(loginTime: str, logoutTime: str) -> int:
login = int(loginTime[:2]) * 60 + int(loginTime[3:])
logout = int(logoutTime[:2]) * 60 + int(logoutTime[3:])
if logout < login:
logout += 1440
login_rounded = ((login + 14) // 15) * 15
logout_rounded = (logout // 15) * 15
return max(0, (logout_rounded - login_rounded) // 15)
The first two lines parse each time string into total minutes. We grab the hours with [:2] and the minutes with [3:], multiply hours by 60, and add. This avoids using split(":") and keeps the parsing minimal.
The wraparound check on line 5 handles sessions that cross midnight. If logout is numerically smaller than login, we add a full day (1440 minutes) to logout. For example, login "21:00" (1260) and logout "03:00" (180) becomes login=1260 and logout=1620.
Lines 7 and 8 do the boundary snapping. The expression (login + 14) // 15 * 15 rounds up to the nearest multiple of 15 using integer arithmetic. Adding 14 before floor-dividing by 15 is a standard ceiling-division trick. The logout rounding is simpler: logout // 15 * 15 just drops any remainder, rounding down. The final line takes the difference, divides by 15 to count blocks, and clamps to zero.
Complexity analysis
| Complexity | Why | |
|---|---|---|
| Time | O(1) | Fixed number of arithmetic operations, no loops |
| Space | O(1) | Only a handful of integer variables |
This is optimal. The input is always two fixed-length strings, so there is nothing to iterate over. The entire solution runs in constant time and constant space.
The building blocks
-
Ceiling division with integers. The expression
(x + d - 1) // dcomputes the ceiling ofx / dwithout floating-point math. You will see this pattern in problems involving page counts, batch sizes, and any scenario where you need to round up to the next whole unit. -
Time-to-minutes conversion. Converting
"HH:MM"strings into a single integer (total minutes since midnight) collapses a two-part representation into one dimension. This simplifies comparisons and arithmetic. The same technique works for problems involving time differences, scheduling, and interval overlap. -
Wraparound handling with offset. When a circular range can cross a boundary (midnight, array end, modular limit), adding the period length to the smaller value linearizes the range. This avoids special-case branching for the wrap condition.
Edge cases
- Login and logout on exact boundaries.
"09:00"to"09:45"produces 3 full rounds. No rounding needed since both times already sit on 15-minute marks. - Session shorter than 15 minutes.
"09:01"to"09:14"rounds login up to"09:15"and logout down to"09:00". The gap is negative, somax(0, ...)returns 0. - Login equals logout. The session spans a full 24 hours. Logout gets 1440 added, giving 96 full rounds (the entire day).
- Midnight wraparound.
"23:50"to"00:10"crosses midnight. Login rounds up to"00:00"(1440) and logout becomes"00:10"(10 + 1440 = 1450), which rounds down to"00:00"(1440). The gap is 0, so 0 full rounds. - Both times identical and on a boundary.
"12:00"to"12:00"spans 24 hours, producing 96 rounds.
From understanding to recall
The math here is compact, just a few lines of arithmetic. But under interview pressure, it is easy to forget whether you round login up or down, whether the wraparound check uses strict or non-strict comparison, or whether the final formula divides by 15 before or after the subtraction. These small details make the difference between a correct solution and a frustrating off-by-one bug.
Spaced repetition helps you internalize those details. You practice writing the boundary-snapping formula from scratch at increasing intervals. After a few rounds, the ceiling-division trick and the wraparound offset become automatic. You see "count 15-minute intervals" and the code flows without hesitation.
The building blocks in this problem (ceiling division, time conversion, circular wraparound) appear across dozens of other LeetCode problems. Drilling them independently means you recognize each piece instantly when it shows up in a new context.
Related posts
- Minimum Rounds to Complete All Tasks - Another counting rounds problem
- Number of Good Pairs - Simple counting with math
- Palindrome Number - Working with numeric properties