1736. Latest Time by Replacing Hidden Digits
Problem Description
You are given a time string in the format hh:mm
where some digits are hidden and replaced with the character ?
. Your task is to find the latest (maximum) valid time possible by replacing all the ?
characters with appropriate digits.
The valid time must be between 00:00
and 23:59
(inclusive), following the 24-hour format where:
- Hours range from
00
to23
- Minutes range from
00
to59
For example, if the input is "2?:?0"
, you should return "23:50"
as this is the latest valid time you can create by replacing the ?
characters.
The strategy is to maximize each digit position from left to right:
- For the first hour digit (position 0): It can be at most
2
, but if the second hour digit is4
or greater, it can only be1
- For the second hour digit (position 1): It can be at most
9
if the first digit is0
or1
, but only up to3
if the first digit is2
- For the first minute digit (position 3): It can be at most
5
- For the second minute digit (position 4): It can be at most
9
Intuition
Since we want the latest (maximum) possible time, we should try to maximize each digit position from left to right. The key insight is that each digit has constraints based on its position and potentially on the values of other digits.
Think about how time works in 24-hour format:
- Hours can range from
00
to23
- Minutes can range from
00
to59
This means each position has a maximum possible value, but these maximums are interdependent. For the hour digits, if we have 2
as the first digit, the second digit can only go up to 3
(giving us 23
). But if the first digit is 0
or 1
, the second digit can go all the way up to 9
.
The greedy approach works here because we process digits from left to right, and each position's maximum value depends only on positions we've already determined or can peek at. When we encounter a ?
, we want to place the largest valid digit possible at that position.
For the hour positions:
- If the first digit is
?
and the second digit is4
or higher, we can only use1
(since24
,25
, etc. are invalid) - If the first digit is
?
and the second digit is3
or lower (or also?
), we can use2
- If the second digit is
?
and the first digit is2
, we can only use up to3
- If the second digit is
?
and the first digit is less than2
, we can use up to9
For the minute positions, it's simpler:
- The first minute digit can be at most
5
(since minutes go up to59
) - The second minute digit can always be
9
when it's?
This greedy strategy guarantees the maximum time because we're maximizing the most significant digits first, which has the greatest impact on the overall value.
Learn more about Greedy patterns.
Solution Approach
The implementation uses a greedy approach to process each character of the time string sequentially. We convert the string to a list for easier manipulation since strings are immutable in Python.
Here's the step-by-step implementation:
-
Convert string to list:
t = list(time)
allows us to modify individual characters. -
Process the first hour digit (index 0):
if t[0] == '?': t[0] = '1' if '4' <= t[1] <= '9' else '2'
- If the second hour digit is between
4
and9
, we can only use1
(since24:xx
or higher would be invalid) - Otherwise, we use
2
to maximize the hour value
- If the second hour digit is between
-
Process the second hour digit (index 1):
if t[1] == '?': t[1] = '3' if t[0] == '2' else '9'
- If the first hour digit is
2
, the maximum second digit is3
(giving us23
) - Otherwise (when first digit is
0
or1
), we can use9
- If the first hour digit is
-
Process the first minute digit (index 3):
if t[3] == '?': t[3] = '5'
- The maximum value is
5
since minutes range from00
to59
- The maximum value is
-
Process the second minute digit (index 4):
if t[4] == '?': t[4] = '9'
- This can always be
9
to maximize the minutes
- This can always be
-
Return the result:
return ''.join(t)
converts the list back to a string.
The algorithm runs in O(1)
time complexity since we're processing a fixed-length string of 5 characters. The space complexity is also O(1)
as we only create a list of constant size.
Note that we skip index 2 since it's always a colon :
and never needs replacement.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the example "2?:?0"
to see how our greedy approach finds the maximum time "23:50"
.
Initial state: t = ['2', '?', ':', '?', '0']
Step 1 - Process first hour digit (index 0):
t[0] = '2'
(not a?
, so we skip this step)- State remains:
['2', '?', ':', '?', '0']
Step 2 - Process second hour digit (index 1):
t[1] = '?'
, so we need to replace it- Check
t[0]
: it's'2'
- Since the first hour digit is
'2'
, we can only use up to'3'
to keep the hour valid (β€ 23) - Set
t[1] = '3'
- State becomes:
['2', '3', ':', '?', '0']
Step 3 - Process first minute digit (index 3):
t[3] = '?'
, so we need to replace it- For minutes to be valid (00-59), the first minute digit can be at most
'5'
- Set
t[3] = '5'
- State becomes:
['2', '3', ':', '5', '0']
Step 4 - Process second minute digit (index 4):
t[4] = '0'
(not a?
, so we skip this step)- State remains:
['2', '3', ':', '5', '0']
Step 5 - Convert back to string:
- Join the list:
''.join(t)
="23:50"
The algorithm successfully found the maximum valid time by greedily maximizing each ?
position while respecting the constraints of valid 24-hour time format.
Solution Implementation
1class Solution:
2 def maximumTime(self, time: str) -> str:
3 # Convert string to list for mutation
4 time_list = list(time)
5
6 # Handle first hour digit (tens place of hour)
7 # Can be '2' if second digit is 0-3 or '?', otherwise must be '1'
8 if time_list[0] == '?':
9 if time_list[1] == '?' or time_list[1] <= '3':
10 time_list[0] = '2'
11 else:
12 time_list[0] = '1'
13
14 # Handle second hour digit (ones place of hour)
15 # Can be '3' if first digit is '2', otherwise can be '9'
16 if time_list[1] == '?':
17 if time_list[0] == '2':
18 time_list[1] = '3'
19 else:
20 time_list[1] = '9'
21
22 # Handle first minute digit (tens place of minute)
23 # Maximum valid value is '5' (for 59 minutes)
24 if time_list[3] == '?':
25 time_list[3] = '5'
26
27 # Handle second minute digit (ones place of minute)
28 # Maximum valid value is '9' (for X9 minutes)
29 if time_list[4] == '?':
30 time_list[4] = '9'
31
32 # Convert list back to string and return
33 return ''.join(time_list)
34
1class Solution {
2 public String maximumTime(String time) {
3 // Convert the time string to a character array for easier manipulation
4 char[] timeArray = time.toCharArray();
5
6 // Handle the first digit of hours (tens place)
7 if (timeArray[0] == '?') {
8 // If second digit is 4-9, first digit can only be 1 (max would be 19)
9 // Otherwise, first digit can be 2 (max would be 23)
10 timeArray[0] = (timeArray[1] >= '4' && timeArray[1] <= '9') ? '1' : '2';
11 }
12
13 // Handle the second digit of hours (ones place)
14 if (timeArray[1] == '?') {
15 // If first digit is 2, max second digit is 3 (to make 23)
16 // Otherwise, max second digit is 9 (to make 09, 19)
17 timeArray[1] = (timeArray[0] == '2') ? '3' : '9';
18 }
19
20 // Handle the first digit of minutes (tens place)
21 if (timeArray[3] == '?') {
22 // Maximum value for tens place of minutes is 5 (59 minutes max)
23 timeArray[3] = '5';
24 }
25
26 // Handle the second digit of minutes (ones place)
27 if (timeArray[4] == '?') {
28 // Maximum value for ones place of minutes is 9
29 timeArray[4] = '9';
30 }
31
32 // Convert the character array back to a string and return
33 return new String(timeArray);
34 }
35}
36
1class Solution {
2public:
3 string maximumTime(string time) {
4 // Handle the first digit of hours (tens place)
5 // If it's '?', we need to determine the maximum valid value
6 if (time[0] == '?') {
7 // If the second digit is between '4' and '9', the first digit can only be '1'
8 // (since valid hours are 00-23, we can't have 24-29)
9 // Otherwise, we can use '2' to maximize the hour value
10 time[0] = (time[1] >= '4' && time[1] <= '9') ? '1' : '2';
11 }
12
13 // Handle the second digit of hours (ones place)
14 // If it's '?', we need to determine the maximum valid value
15 if (time[1] == '?') {
16 // If the first digit is '2', we can only go up to '3' (for 23:xx)
17 // Otherwise (first digit is 0 or 1), we can use '9' to maximize
18 time[1] = (time[0] == '2') ? '3' : '9';
19 }
20
21 // Handle the first digit of minutes (tens place)
22 // Maximum value is '5' (since minutes range from 00-59)
23 if (time[3] == '?') {
24 time[3] = '5';
25 }
26
27 // Handle the second digit of minutes (ones place)
28 // Maximum value is always '9' (for x9 minutes)
29 if (time[4] == '?') {
30 time[4] = '9';
31 }
32
33 return time;
34 }
35};
36
1/**
2 * Given a time string with some digits replaced by '?', returns the maximum valid time
3 * that can be obtained by replacing all '?' characters with digits.
4 * Time format is "HH:MM" where HH is 00-23 and MM is 00-59.
5 *
6 * @param time - A time string in "HH:MM" format where some digits may be replaced by '?'
7 * @return The maximum valid time string after replacing all '?' characters
8 */
9function maximumTime(time: string): string {
10 // Convert string to array for easier character manipulation
11 const timeArray: string[] = Array.from(time);
12
13 // Handle first digit of hour (tens place)
14 // If first digit is '?', it can be '2' if second digit is 0-3, otherwise '1'
15 if (timeArray[0] === '?') {
16 timeArray[0] = timeArray[1] >= '4' && timeArray[1] <= '9' ? '1' : '2';
17 }
18
19 // Handle second digit of hour (ones place)
20 // If second digit is '?', it can be '3' if first digit is '2', otherwise '9'
21 if (timeArray[1] === '?') {
22 timeArray[1] = timeArray[0] === '2' ? '3' : '9';
23 }
24
25 // Handle first digit of minute (tens place)
26 // Maximum value is '5' for valid minutes (00-59)
27 if (timeArray[3] === '?') {
28 timeArray[3] = '5';
29 }
30
31 // Handle second digit of minute (ones place)
32 // Maximum value is always '9' for ones place
33 if (timeArray[4] === '?') {
34 timeArray[4] = '9';
35 }
36
37 // Join the array back into a string and return
38 return timeArray.join('');
39}
40
Time and Space Complexity
The time complexity is O(1)
because the algorithm performs a fixed number of operations regardless of input. The code examines and potentially modifies exactly 4 character positions (indices 0, 1, 3, and 4) in the time string, with each position requiring at most one comparison and one assignment operation. Converting the string to a list with list(time)
takes O(5)
time since the time format is always "HH:MM" (5 characters), and joining the list back to a string with ''.join(t)
also takes O(5)
time. Since all operations are constant, the overall time complexity is O(1)
.
The space complexity is O(1)
because the algorithm uses a fixed amount of extra space. The list t
created from the input string always contains exactly 5 characters (for the "HH:MM" format), which is a constant amount of space that doesn't scale with any input parameter. No additional data structures are created that depend on input size, making the space complexity constant at O(1)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Order of Evaluation for Hour Digits
The Pitfall:
A critical mistake occurs when determining the first hour digit without properly checking the second hour digit. The code checks if time_list[1] <= '3'
, but this comparison is problematic when time_list[1]
is a non-?
character between '4' and '9'.
Consider the input "?4:15"
:
- The condition
time_list[1] <= '3'
performs string comparison:'4' <= '3'
evaluates toFalse
(correct by luck) - However, the logic
if time_list[1] == '?' or time_list[1] <= '3'
is semantically incorrect because we're comparing characters, not integers
Why This Happens:
Python compares strings lexicographically, so '4' <= '3'
returns False
, but this works accidentally. The real issue is conceptual - we should be comparing numeric values or characters explicitly.
2. The Correct Solution
class Solution:
def maximumTime(self, time: str) -> str:
time_list = list(time)
# Handle first hour digit - check second digit properly
if time_list[0] == '?':
# Check if second digit forces us to use '1'
if time_list[1] in '456789':
time_list[0] = '1'
else:
# Second digit is '?', '0', '1', '2', or '3'
time_list[0] = '2'
# Handle second hour digit
if time_list[1] == '?':
if time_list[0] == '2':
time_list[1] = '3'
else:
time_list[1] = '9'
# Handle first minute digit
if time_list[3] == '?':
time_list[3] = '5'
# Handle second minute digit
if time_list[4] == '?':
time_list[4] = '9'
return ''.join(time_list)
Key Improvements:
- Uses
in '456789'
for explicit character checking rather than ambiguous string comparison - Makes the logic clearer: if the second hour digit is 4 or higher, we must use '1' for the first digit
- Avoids relying on string comparison behavior that might not be immediately obvious to readers
3. Alternative Robust Approach
For even better clarity, you could convert to integers when needed:
if time_list[0] == '?':
if time_list[1] != '?' and int(time_list[1]) >= 4:
time_list[0] = '1'
else:
time_list[0] = '2'
This approach explicitly handles the numeric comparison and makes the intent crystal clear.
A person thinks of a number between 1 and 1000. You may ask any number questions to them, provided that the question can be answered with either "yes" or "no".
What is the minimum number of questions you needed to ask so that you are guaranteed to know the number that the person is thinking?
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!