539. Minimum Time Difference
Problem Description
You are given a list of time points in 24-hour format as strings in the format "HH:MM"
, where HH
represents hours (00-23) and MM
represents minutes (00-59). Your task is to find the minimum difference in minutes between any two time points in the list.
For example, if you have time points ["23:59", "00:00"]
, the minimum difference would be 1 minute (from 23:59 to 00:00 the next day).
The key insight is that time is circular - after 23:59
comes 00:00
, so you need to consider both the forward difference and the "wrap-around" difference when comparing times.
The solution converts each time point to total minutes since midnight (e.g., "13:14"
becomes 13 × 60 + 14 = 794
minutes), sorts these values, and then checks the differences between consecutive times. To handle the circular nature of time, it also adds the first time plus 1440 minutes (24 hours) to the end of the sorted list, allowing the comparison between the last and first times across the day boundary.
Since there are only 1440 possible distinct minute values in a 24-hour period (24 × 60), if the input has more than 1440 time points, there must be duplicates, meaning the minimum difference is 0.
Intuition
The first observation is that working with time strings like "HH:MM"
is cumbersome for comparison. Converting them to a single unit (total minutes from midnight) makes calculations much simpler. For instance, "02:30"
becomes 2 × 60 + 30 = 150
minutes.
Once we have all times as minutes, finding the minimum difference between any two times seems like we need to check all pairs - but that would be inefficient. The key insight is that the minimum difference will always occur between two times that are adjacent when sorted. Why? Because if times A and C have time B between them when sorted, the difference between A and C will always be larger than both A-B and B-C differences.
So we sort the times and check consecutive pairs. However, there's a catch - time is circular! The difference between 23:50
and 00:10
isn't 23 × 60 + 40 = 1420
minutes, but rather 20
minutes (going forward from 23:50
to 00:10
the next day).
To handle this circular nature elegantly, we add the first time point plus 1440
(24 hours in minutes) to the end of our sorted list. This creates a "virtual" next-day occurrence of the earliest time, allowing us to calculate the wrap-around difference between the last and first times naturally as part of checking consecutive pairs.
The optimization about checking if there are more than 1440
time points comes from the pigeonhole principle - there are only 1440
possible minute values in a day, so if we have more time points than that, at least two must be identical, giving us a minimum difference of 0
.
Solution Approach
Let's walk through the implementation step by step:
Step 1: Early Return for Duplicates
if len(timePoints) > 1440:
return 0
Since there are only 24 × 60 = 1440
possible distinct minute values in a 24-hour period, if we have more than 1440 time points, the pigeonhole principle guarantees duplicates exist, so we return 0
immediately.
Step 2: Convert Time Strings to Minutes
nums = sorted(int(x[:2]) * 60 + int(x[3:]) for x in timePoints)
We convert each time string to minutes using a list comprehension:
x[:2]
extracts the hours (first two characters)x[3:]
extracts the minutes (characters after the colon)- Hours are multiplied by 60 and added to minutes to get total minutes from midnight
- The result is immediately sorted in ascending order
For example, "13:14"
becomes 13 × 60 + 14 = 794
minutes.
Step 3: Handle Circular Time
nums.append(nums[0] + 1440)
To handle the wrap-around case (e.g., the difference between 23:59
and 00:01
), we append the smallest time plus 1440 minutes (24 hours) to the end of the sorted list. This creates a virtual "next day" occurrence of the earliest time.
Step 4: Find Minimum Difference
return min(b - a for a, b in pairwise(nums))
Using the pairwise
function (which pairs consecutive elements), we calculate the difference between each pair of adjacent times in the sorted list. The min
function returns the smallest difference among all pairs.
The pairwise
function generates pairs like (nums[0], nums[1])
, (nums[1], nums[2])
, ..., (nums[n-1], nums[n])
where the last pair includes our appended wrap-around value.
This approach ensures we check all meaningful adjacent differences, including the circular difference between the last and first times, in O(n log n)
time due to sorting.
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 an example with timePoints = ["23:59", "00:00", "12:30", "23:45"]
.
Step 1: Check for duplicates
- We have 4 time points, which is less than 1440, so we continue.
Step 2: Convert to minutes and sort
- "23:59" → 23 × 60 + 59 = 1439 minutes
- "00:00" → 0 × 60 + 0 = 0 minutes
- "12:30" → 12 × 60 + 30 = 750 minutes
- "23:45" → 23 × 60 + 45 = 1425 minutes
After sorting: nums = [0, 750, 1425, 1439]
Step 3: Handle circular time
- Append the first time + 1440:
0 + 1440 = 1440
- Now:
nums = [0, 750, 1425, 1439, 1440]
Step 4: Calculate consecutive differences
- Pair 1: (0, 750) → difference = 750 - 0 = 750 minutes
- Pair 2: (750, 1425) → difference = 1425 - 750 = 675 minutes
- Pair 3: (1425, 1439) → difference = 1439 - 1425 = 14 minutes
- Pair 4: (1439, 1440) → difference = 1440 - 1439 = 1 minute
The last pair (1439, 1440) represents the wrap-around difference between "23:59" and "00:00" the next day. Without the circular handling, we might incorrectly calculate this as 1439 - 0 = 1439 minutes!
Result: The minimum difference is 1 minute (between "23:59" and "00:00").
Solution Implementation
1class Solution:
2 def findMinDifference(self, timePoints: List[str]) -> int:
3 # If there are more than 1440 time points (total minutes in a day),
4 # by pigeonhole principle, at least two must be the same
5 if len(timePoints) > 1440:
6 return 0
7
8 # Convert all time strings to minutes since midnight and sort them
9 # For "HH:MM" format: extract hours (first 2 chars) * 60 + minutes (chars 3-4)
10 minutes_list = sorted(int(time[:2]) * 60 + int(time[3:]) for time in timePoints)
11
12 # Add the first time + 1440 (24 hours) to handle circular difference
13 # This accounts for the wrap-around case (e.g., 23:59 to 00:01)
14 minutes_list.append(minutes_list[0] + 1440)
15
16 # Find the minimum difference between consecutive times
17 # pairwise creates pairs of consecutive elements: (a, b), (b, c), (c, d)...
18 from itertools import pairwise
19 return min(b - a for a, b in pairwise(minutes_list))
20
1class Solution {
2 public int findMinDifference(List<String> timePoints) {
3 // If there are more than 1440 time points (24 * 60 minutes in a day),
4 // by pigeonhole principle, at least two must be the same
5 if (timePoints.size() > 1440) {
6 return 0;
7 }
8
9 int n = timePoints.size();
10 // Create array with size n+1 to store converted minutes and handle circular case
11 int[] minutesArray = new int[n + 1];
12
13 // Convert each time point from "HH:MM" format to total minutes
14 for (int i = 0; i < n; i++) {
15 String[] timeParts = timePoints.get(i).split(":");
16 int hours = Integer.parseInt(timeParts[0]);
17 int minutes = Integer.parseInt(timeParts[1]);
18 minutesArray[i] = hours * 60 + minutes;
19 }
20
21 // Sort the time points in ascending order
22 Arrays.sort(minutesArray, 0, n);
23
24 // Add the first time point + 1440 minutes (24 hours) to handle circular difference
25 // This helps calculate the difference between the last and first time point
26 minutesArray[n] = minutesArray[0] + 1440;
27
28 // Initialize minimum difference with a large value (2^30)
29 int minDifference = 1 << 30;
30
31 // Find the minimum difference between consecutive time points
32 for (int i = 1; i <= n; i++) {
33 int currentDifference = minutesArray[i] - minutesArray[i - 1];
34 minDifference = Math.min(minDifference, currentDifference);
35 }
36
37 return minDifference;
38 }
39}
40
1class Solution {
2public:
3 int findMinDifference(vector<string>& timePoints) {
4 // If there are more than 1440 time points (minutes in a day),
5 // by pigeonhole principle, at least two must be the same
6 if (timePoints.size() > 1440) {
7 return 0;
8 }
9
10 int n = timePoints.size();
11 // Create array to store time points in minutes, with extra space for wraparound
12 vector<int> minutesArray(n + 1);
13
14 // Convert each time point from "HH:MM" format to total minutes
15 for (int i = 0; i < n; ++i) {
16 int hours = stoi(timePoints[i].substr(0, 2));
17 int minutes = stoi(timePoints[i].substr(3, 2));
18 minutesArray[i] = hours * 60 + minutes;
19 }
20
21 // Sort the time points in ascending order
22 sort(minutesArray.begin(), minutesArray.begin() + n);
23
24 // Add the first time point + 1440 minutes (24 hours) to handle circular wraparound
25 // This helps calculate the difference between the last and first time points
26 minutesArray[n] = minutesArray[0] + 1440;
27
28 // Find the minimum difference between consecutive time points
29 int minDifference = INT_MAX;
30 for (int i = 1; i <= n; ++i) {
31 minDifference = min(minDifference, minutesArray[i] - minutesArray[i - 1]);
32 }
33
34 return minDifference;
35 }
36};
37
1/**
2 * Finds the minimum time difference between any two time points in minutes
3 * @param timePoints - Array of time strings in "HH:MM" format
4 * @returns The minimum difference in minutes between any two time points
5 */
6function findMinDifference(timePoints: string[]): number {
7 // If there are more than 1440 time points (total minutes in a day),
8 // by pigeonhole principle, at least two must be the same
9 if (timePoints.length > 1440) {
10 return 0;
11 }
12
13 const timePointCount: number = timePoints.length;
14 // Create array with extra slot for circular comparison
15 const minutesArray: number[] = new Array(timePointCount + 1);
16
17 // Convert all time strings to minutes since midnight
18 for (let i = 0; i < timePointCount; i++) {
19 const [hours, minutes] = timePoints[i].split(':').map(Number);
20 minutesArray[i] = hours * 60 + minutes;
21 }
22
23 // Sort times in ascending order
24 minutesArray.sort((a, b) => a - b);
25
26 // Add first time + 1440 (24 hours) to handle circular difference
27 // This allows comparison between last and first time across midnight
28 minutesArray[timePointCount] = minutesArray[0] + 1440;
29
30 // Initialize minimum difference with a large value (2^30)
31 let minimumDifference: number = 1 << 30;
32
33 // Compare each adjacent pair of times to find minimum difference
34 for (let i = 1; i <= timePointCount; i++) {
35 minimumDifference = Math.min(minimumDifference, minutesArray[i] - minutesArray[i - 1]);
36 }
37
38 return minimumDifference;
39}
40
Time and Space Complexity
Time Complexity: O(n log n)
, where n
is the number of time points.
The algorithm performs the following operations:
- Converting each time string to minutes takes
O(n)
time, iterating through alln
time points - Sorting the converted time values takes
O(n log n)
time using Python's built-in sort - Appending one element to the list takes
O(1)
time - Finding the minimum difference using
pairwise
iterates throughn+1
pairs, takingO(n)
time
The dominant operation is sorting, making the overall time complexity O(n log n)
.
Space Complexity: O(n)
, where n
is the number of time points.
The algorithm uses:
- A list
nums
to store the converted minute values, requiringO(n)
space - The sorted operation in Python creates a new list, using
O(n)
additional space - The
pairwise
function creates an iterator that usesO(1)
space - The generator expression for minimum calculation uses
O(1)
space
The total space complexity is O(n)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Forgetting the Circular Nature of Time
The most common mistake is only checking differences between consecutive sorted times without considering the wrap-around from the last time to the first time across midnight.
Incorrect approach:
def findMinDifference(self, timePoints: List[str]) -> int:
minutes_list = sorted(int(time[:2]) * 60 + int(time[3:]) for time in timePoints)
# WRONG: Only checks consecutive pairs, misses wrap-around
return min(minutes_list[i+1] - minutes_list[i] for i in range(len(minutes_list)-1))
This would fail for input like ["00:00", "23:59"]
where the minimum difference is 1 minute (going forward from 23:59 to 00:00), not 1439 minutes (going backward).
Solution: Always append minutes_list[0] + 1440
to handle the circular case, ensuring you check the difference between the last and first times across the day boundary.
2. Not Handling Duplicate Times Efficiently
Another pitfall is not recognizing that duplicate times should immediately return 0, or worse, not realizing that more than 1440 time points guarantees duplicates.
Inefficient approach:
def findMinDifference(self, timePoints: List[str]) -> int:
minutes_list = sorted(int(time[:2]) * 60 + int(time[3:]) for time in timePoints)
# Inefficient: Converts and sorts everything even when duplicates are guaranteed
for i in range(1, len(minutes_list)):
if minutes_list[i] == minutes_list[i-1]:
return 0
# ... continue with normal logic
Solution: Check if len(timePoints) > 1440: return 0
at the very beginning to avoid unnecessary conversions and sorting when duplicates are guaranteed by the pigeonhole principle.
3. Incorrect Time String Parsing
Be careful with string slicing indices when parsing the time format.
Common mistakes:
# WRONG: Using wrong indices
minutes = int(time[0:2]) * 60 + int(time[2:4]) # Missing the colon, gets wrong minutes
# WRONG: Not converting to int before arithmetic
minutes = time[:2] * 60 + time[3:] # String concatenation instead of arithmetic
Solution: Use the correct slicing time[:2]
for hours and time[3:]
for minutes (skipping the colon at index 2), and ensure conversion to int
before performing arithmetic operations.
What does the following code do?
1def f(arr1, arr2):
2 i, j = 0, 0
3 new_arr = []
4 while i < len(arr1) and j < len(arr2):
5 if arr1[i] < arr2[j]:
6 new_arr.append(arr1[i])
7 i += 1
8 else:
9 new_arr.append(arr2[j])
10 j += 1
11 new_arr.extend(arr1[i:])
12 new_arr.extend(arr2[j:])
13 return new_arr
14
1public static List<Integer> f(int[] arr1, int[] arr2) {
2 int i = 0, j = 0;
3 List<Integer> newArr = new ArrayList<>();
4
5 while (i < arr1.length && j < arr2.length) {
6 if (arr1[i] < arr2[j]) {
7 newArr.add(arr1[i]);
8 i++;
9 } else {
10 newArr.add(arr2[j]);
11 j++;
12 }
13 }
14
15 while (i < arr1.length) {
16 newArr.add(arr1[i]);
17 i++;
18 }
19
20 while (j < arr2.length) {
21 newArr.add(arr2[j]);
22 j++;
23 }
24
25 return newArr;
26}
27
1function f(arr1, arr2) {
2 let i = 0, j = 0;
3 let newArr = [];
4
5 while (i < arr1.length && j < arr2.length) {
6 if (arr1[i] < arr2[j]) {
7 newArr.push(arr1[i]);
8 i++;
9 } else {
10 newArr.push(arr2[j]);
11 j++;
12 }
13 }
14
15 while (i < arr1.length) {
16 newArr.push(arr1[i]);
17 i++;
18 }
19
20 while (j < arr2.length) {
21 newArr.push(arr2[j]);
22 j++;
23 }
24
25 return newArr;
26}
27
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
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
Want a Structured Path to Master System Design Too? Don’t Miss This!