2224. Minimum Number of Operations to Convert Time
Problem Description
You are given two time strings in 24-hour format ("HH:MM"), where:
current
represents the starting timecorrect
represents the target time you want to reach
The task is to convert current
time to correct
time using the minimum number of operations.
In each operation, you can add exactly one of these time increments to the current time:
- 60 minutes (1 hour)
- 15 minutes
- 5 minutes
- 1 minute
You can use any combination of these operations and repeat them as many times as needed.
For example, if current = "02:30"
and correct = "04:35"
, you need to add 2 hours and 5 minutes total (125 minutes). The optimal approach would be:
- Add 60 minutes twice (2 operations for 120 minutes)
- Add 5 minutes once (1 operation for 5 minutes)
- Total: 3 operations
The solution converts both times to total minutes since midnight, calculates the difference, then greedily uses the largest possible increments first. It divides the remaining difference by each increment size (60, 15, 5, 1) in descending order, adding the quotient to the operation count and continuing with the remainder.
Intuition
The key insight is that we want to minimize the total number of operations, which means we should use the largest possible increments whenever we can. This is a classic greedy approach.
Think of it like making change with coins - if you need to give 67 cents in change and you have quarters (25Β’), dimes (10Β’), nickels (5Β’), and pennies (1Β’), you'd naturally start with the largest coins first: 2 quarters, 1 dime, 1 nickel, and 2 pennies. This gives you the minimum number of coins.
The same principle applies here. We have four "time coins" of values 60
, 15
, 5
, and 1
minutes. To bridge the gap between current
and correct
times with the fewest operations, we should:
- First, convert both times to minutes for easier calculation (hours Γ 60 + minutes)
- Find the difference we need to cover
- Use as many 60-minute increments as possible
- Then use as many 15-minute increments as possible from what remains
- Then 5-minute increments
- Finally, 1-minute increments for any remainder
This greedy strategy works because each larger increment is divisible by or contains the smaller ones in a way that doesn't create conflicts. We can always break down a larger increment into smaller ones if needed, but using larger increments first guarantees fewer total operations.
For instance, if we need to add 127 minutes:
127 Γ· 60 = 2
remainder7
β Use 2 operations of 60 minutes7 Γ· 15 = 0
remainder7
β Can't use 15-minute increments7 Γ· 5 = 1
remainder2
β Use 1 operation of 5 minutes2 Γ· 1 = 2
remainder0
β Use 2 operations of 1 minute- Total:
2 + 0 + 1 + 2 = 5
operations
Learn more about Greedy patterns.
Solution Approach
The implementation follows a straightforward greedy algorithm:
Step 1: Convert times to minutes
a = int(current[:2]) * 60 + int(current[3:])
b = int(correct[:2]) * 60 + int(correct[3:])
- Extract hours using string slicing
[:2]
and minutes using[3:]
- Convert both times to total minutes since midnight
- For example, "14:30" becomes
14 * 60 + 30 = 870
minutes
Step 2: Calculate the difference
ans, d = 0, b - a
- Initialize
ans
to track the total number of operations - Calculate
d
as the difference in minutes we need to add - Since we can only increase time,
correct
must be greater than or equal tocurrent
Step 3: Apply greedy approach
for i in [60, 15, 5, 1]: ans += d // i d %= i
- Iterate through increment sizes in descending order:
[60, 15, 5, 1]
- For each increment size
i
:d // i
gives the maximum number of times we can use this increment- Add this count to our total operations
- Update
d
to the remainder using modulo operatord %= i
- This remainder will be handled by smaller increments
Example walkthrough:
If current = "11:00"
and correct = "11:22"
:
- Convert to minutes:
a = 660
,b = 682
- Difference:
d = 22
- Process increments:
60
:22 // 60 = 0
, remainder =22
15
:22 // 15 = 1
, remainder =7
5
:7 // 5 = 1
, remainder =2
1
:2 // 1 = 2
, remainder =0
- Total operations:
0 + 1 + 1 + 2 = 4
The algorithm has a time complexity of O(1)
since we always iterate through exactly 4 increment values, and space complexity of O(1)
as we only use a few variables.
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 the solution with current = "09:43"
and correct = "11:01"
.
Step 1: Convert times to minutes
current = "09:43"
β9 * 60 + 43 = 540 + 43 = 583
minutescorrect = "11:01"
β11 * 60 + 1 = 660 + 1 = 661
minutes
Step 2: Calculate the difference
- We need to add:
661 - 583 = 78
minutes - Initialize operation counter:
ans = 0
Step 3: Apply greedy approach with increments [60, 15, 5, 1]
For 60-minute increment:
- How many times can 60 fit into 78?
78 Γ· 60 = 1
(with remainder) - Add 1 operation:
ans = 0 + 1 = 1
- Remaining time:
78 % 60 = 18
minutes
For 15-minute increment:
- How many times can 15 fit into 18?
18 Γ· 15 = 1
(with remainder) - Add 1 operation:
ans = 1 + 1 = 2
- Remaining time:
18 % 15 = 3
minutes
For 5-minute increment:
- How many times can 5 fit into 3?
3 Γ· 5 = 0
- Add 0 operations:
ans = 2 + 0 = 2
- Remaining time:
3 % 5 = 3
minutes
For 1-minute increment:
- How many times can 1 fit into 3?
3 Γ· 1 = 3
- Add 3 operations:
ans = 2 + 3 = 5
- Remaining time:
3 % 1 = 0
minutes
Result: We need 5 operations total:
- 1 Γ 60 minutes
- 1 Γ 15 minutes
- 0 Γ 5 minutes
- 3 Γ 1 minute
This gives us exactly 60 + 15 + 0 + 3 = 78
minutes, transforming 09:43 β 11:01.
Solution Implementation
1class Solution:
2 def convertTime(self, current: str, correct: str) -> int:
3 # Convert current time from "HH:MM" format to total minutes
4 current_minutes = int(current[:2]) * 60 + int(current[3:])
5
6 # Convert correct/target time from "HH:MM" format to total minutes
7 target_minutes = int(correct[:2]) * 60 + int(correct[3:])
8
9 # Calculate the difference in minutes between target and current time
10 operations_count = 0
11 time_difference = target_minutes - current_minutes
12
13 # Greedily use the largest possible time increments (60, 15, 5, 1 minutes)
14 # to minimize the number of operations needed
15 time_increments = [60, 15, 5, 1]
16
17 for increment in time_increments:
18 # Add the number of times we can use this increment
19 operations_count += time_difference // increment
20 # Update remaining time difference
21 time_difference %= increment
22
23 return operations_count
24
1class Solution {
2 public int convertTime(String current, String correct) {
3 // Extract hours and minutes from current time and convert to total minutes
4 int currentMinutes = Integer.parseInt(current.substring(0, 2)) * 60
5 + Integer.parseInt(current.substring(3));
6
7 // Extract hours and minutes from correct time and convert to total minutes
8 int correctMinutes = Integer.parseInt(correct.substring(0, 2)) * 60
9 + Integer.parseInt(correct.substring(3));
10
11 // Initialize operation counter and calculate time difference in minutes
12 int operationCount = 0;
13 int timeDifference = correctMinutes - currentMinutes;
14
15 // Array of possible operation values in descending order (60, 15, 5, 1 minutes)
16 int[] operations = {60, 15, 5, 1};
17
18 // Greedily use the largest possible operations first
19 for (int operation : operations) {
20 // Add the number of times we can use this operation
21 operationCount += timeDifference / operation;
22 // Update remaining time difference
23 timeDifference %= operation;
24 }
25
26 return operationCount;
27 }
28}
29
1class Solution {
2public:
3 int convertTime(string current, string correct) {
4 // Convert time strings (HH:MM format) to total minutes
5 // Extract hours (first 2 chars) and multiply by 60, then add minutes (chars 3-4)
6 int currentMinutes = stoi(current.substr(0, 2)) * 60 + stoi(current.substr(3, 2));
7 int targetMinutes = stoi(correct.substr(0, 2)) * 60 + stoi(correct.substr(3, 2));
8
9 // Initialize operation counter and calculate time difference
10 int operationCount = 0;
11 int timeDifference = targetMinutes - currentMinutes;
12
13 // Define available time increments in descending order (greedy approach)
14 // Using 60, 15, 5, and 1 minute increments
15 vector<int> timeIncrements = {60, 15, 5, 1};
16
17 // Greedily use the largest possible increments first
18 for (int increment : timeIncrements) {
19 // Add the number of times we can use this increment
20 operationCount += timeDifference / increment;
21 // Update remaining time difference
22 timeDifference %= increment;
23 }
24
25 return operationCount;
26 }
27};
28
1function convertTime(current: string, correct: string): number {
2 // Convert time strings (HH:MM format) to total minutes
3 // Extract hours (first 2 chars) and multiply by 60, then add minutes (chars 3-4)
4 const currentMinutes: number = parseInt(current.substring(0, 2)) * 60 + parseInt(current.substring(3, 5));
5 const targetMinutes: number = parseInt(correct.substring(0, 2)) * 60 + parseInt(correct.substring(3, 5));
6
7 // Initialize operation counter and calculate time difference
8 let operationCount: number = 0;
9 let timeDifference: number = targetMinutes - currentMinutes;
10
11 // Define available time increments in descending order (greedy approach)
12 // Using 60, 15, 5, and 1 minute increments
13 const timeIncrements: number[] = [60, 15, 5, 1];
14
15 // Greedily use the largest possible increments first
16 for (const increment of timeIncrements) {
17 // Add the number of times we can use this increment
18 operationCount += Math.floor(timeDifference / increment);
19 // Update remaining time difference
20 timeDifference %= increment;
21 }
22
23 return operationCount;
24}
25
Time and Space Complexity
Time Complexity: O(1)
The algorithm performs the following operations:
- Parsing the time strings to extract hours and minutes:
O(1)
since the string format is fixed (HH:MM) - Converting both times to minutes:
O(1)
with two arithmetic operations each - Iterating through a fixed array of 4 elements [60, 15, 5, 1]:
O(4) = O(1)
- For each iteration, performing division and modulo operations:
O(1)
Since all operations are constant time and the loop runs exactly 4 times regardless of input, the overall time complexity is O(1)
.
Space Complexity: O(1)
The algorithm uses only a fixed amount of extra space:
- Variables
a
andb
to store the converted minutes:O(1)
- Variables
ans
andd
to track the operations count and remaining difference:O(1)
- The array
[60, 15, 5, 1]
is a constant-size array:O(1)
- Loop variable
i
:O(1)
No additional space that scales with input size is used, resulting in O(1)
space complexity.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect String Parsing
A common mistake is using wrong indices when extracting hours and minutes from the time string. Some might write:
int(current[0:1])
instead ofint(current[:2])
for hoursint(current[2:])
instead ofint(current[3:])
for minutes (forgetting the colon at index 2)
Solution: Remember the format is "HH:MM" where:
- Hours are at indices 0-1 (use
[:2]
) - Colon is at index 2
- Minutes are at indices 3-4 (use
[3:]
)
2. Handling Time Wraparound
The problem doesn't explicitly state whether times can wrap around midnight. Developers might incorrectly assume that if current > correct
, they need to add 24 hours first:
# Incorrect assumption if current_minutes > target_minutes: target_minutes += 24 * 60 # Adding a full day
Solution: Based on the problem constraints, correct
time is always greater than or equal to current
time within the same day. No wraparound handling is needed.
3. Using Non-Greedy Approach
Some might try to use dynamic programming or recursion unnecessarily:
# Overly complex approach
def minOperations(remaining, increments):
if remaining == 0:
return 0
min_ops = float('inf')
for inc in increments:
if inc <= remaining:
min_ops = min(min_ops, 1 + minOperations(remaining - inc, increments))
return min_ops
Solution: The greedy approach always works optimally here. Using larger increments first guarantees the minimum number of operations because:
- Any combination of smaller increments that equals a larger increment requires more operations
- For example, 60 minutes = 4Γ15 minutes, but using one 60-minute operation is better than four 15-minute operations
4. Integer Division vs Float Division
Using regular division /
instead of integer division //
will cause issues:
# Wrong - produces float ans += d / i # Results in 1.5 instead of 1 for 22/15 # Correct - produces integer ans += d // i # Results in 1 for 22/15
Solution: Always use integer division //
when counting the number of complete increments that fit into the remaining time difference.
What is the best way of checking if an element exists in a sorted array once in terms of time complexity? Select the best that applies.
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
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
Want a Structured Path to Master System Design Too? Donβt Miss This!