Facebook Pixel

3114. Latest Time You Can Obtain After Replacing Characters

EasyStringEnumeration
Leetcode Link

Problem Description

You are given a string s that represents a time in 12-hour format, where some digits might be replaced with question marks ("?").

The 12-hour time format follows the pattern "HH:MM" where:

  • HH represents hours and must be between 00 and 11 (inclusive)
  • MM represents minutes and must be between 00 and 59 (inclusive)
  • The earliest possible time is 00:00 and the latest is 11:59

Your task is to replace all the "?" characters in the string with valid digits to create a valid 12-hour time. Among all possible valid times you can create, you need to return the latest (maximum) possible time.

For example:

  • If s = "1?:?9", you could create times like "10:09", "11:19", "11:29", etc. The latest valid time would be "11:59".
  • If s = "0?:5?", valid times include "00:50", "01:51", "09:59", etc. The latest would be "09:59".

The solution works by trying all possible times from the latest (11:59) to the earliest (00:00), checking if each time matches the pattern given in s (where "?" can match any digit). The first matching time found will be the latest possible time.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

Since we want to find the latest possible valid time, a natural approach is to start checking from the maximum possible time and work our way backwards. This greedy strategy ensures that the first valid time we find will automatically be the latest one.

Think of it like this: if we need to fill in the blanks to make the biggest number possible, we'd try to put the largest digits first. Here, instead of constructing the time digit by digit, we can leverage the fact that there are only a limited number of possible times in 12-hour format - just 12 × 60 = 720 total possibilities.

The key insight is that checking whether a time matches our pattern with "?" wildcards is straightforward - we just need to verify that each non-"?" character in the original string matches the corresponding digit in our candidate time. If they all match, then we can replace the "?" characters with the corresponding digits from that time.

By iterating from 11:59 down to 00:00, we guarantee that:

  1. We explore all possible valid times
  2. The first match we find is the maximum possible time
  3. We don't need complex logic to determine which digit to place where

This brute-force approach is efficient enough because the search space is small (only 720 possibilities), and the matching check for each candidate is O(1) since the string length is fixed at 5 characters.

Solution Approach

The implementation uses a simple enumeration strategy with nested loops to check all possible times from latest to earliest.

Step-by-step breakdown:

  1. Outer loop for hours: Iterate through hours from 11 down to 0 using range(11, -1, -1). This ensures we check the latest hours first.

  2. Inner loop for minutes: For each hour, iterate through minutes from 59 down to 0 using range(59, -1, -1). This ensures we check the latest minutes first for each hour.

  3. Format the time: For each combination of hour h and minute m, create a formatted string t using f"{h:02d}:{m:02d}". The :02d ensures that single-digit numbers are padded with a leading zero (e.g., 9 becomes "09").

  4. Pattern matching: Check if the formatted time t matches the pattern in s:

    • Use zip(s, t) to pair up corresponding characters from both strings
    • For each pair (a, b), verify that either a == "?" (wildcard) or a == b (exact match)
    • The expression all(a == b for a, b in zip(s, t) if a != "?") returns True only if all non-wildcard positions match
  5. Return first match: As soon as we find a time that matches the pattern, return it immediately. Since we're checking from latest to earliest, this guaranteed to be the maximum valid time.

Example walkthrough with s = "1?:?9":

  • Start checking from 11:59: Compare with "1?:?9""1" == "1" ✓, "1" matches "?" ✓, "5" matches "?" ✓, "9" == "9" ✓ → Match found!
  • Return "11:59"

The algorithm has a time complexity of O(1) since we check at most 720 fixed combinations, and space complexity of O(1) as we only use a constant amount of extra space.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with s = "0?:5?":

Step 1: Start from the latest possible time (11:59) and work backwards

We'll check each time to see if it matches our pattern "0?:5?".

Step 2: Check 11:59

  • Compare "11:59" with "0?:5?"
  • Position 0: "1" vs "0" → No match (we need "0", not "1")
  • Skip this time

Step 3: Check 11:58

  • Compare "11:58" with "0?:5?"
  • Position 0: "1" vs "0" → No match
  • Skip this time

Step 4: Continue checking... (skipping hours 11 and 10)

All times starting with "11:" or "10:" will fail because they don't start with "0".

Step 5: Check 09:59

  • Compare "09:59" with "0?:5?"
  • Position 0: "0" vs "0" → Match! ✓
  • Position 1: "9" vs "?" → Match! (wildcard) ✓
  • Position 2: ":" vs ":" → Match! ✓
  • Position 3: "5" vs "5" → Match! ✓
  • Position 4: "9" vs "?" → Match! (wildcard) ✓

Step 6: Return the result

Since all positions match, "09:59" is valid. Because we're checking from latest to earliest, this is the maximum possible time.

The algorithm replaces:

  • The first "?" (position 1) with "9"
  • The second "?" (position 4) with "9"

Final answer: "09:59"

Solution Implementation

1class Solution:
2    def findLatestTime(self, s: str) -> str:
3        # Iterate through all possible times from latest to earliest
4        # Hours: from 11 down to 00
5        for hour in range(11, -1, -1):
6            # Minutes: from 59 down to 00
7            for minute in range(59, -1, -1):
8                # Format the current time as HH:MM string
9                current_time = f"{hour:02d}:{minute:02d}"
10              
11                # Check if current time matches the pattern
12                # Compare each character: if pattern has '?', any digit is valid
13                # If pattern has a specific digit, it must match
14                is_valid_match = all(
15                    pattern_char == time_char 
16                    for pattern_char, time_char in zip(s, current_time) 
17                    if pattern_char != "?"
18                )
19              
20                # Return the first valid time found (which is the latest due to iteration order)
21                if is_valid_match:
22                    return current_time
23
1class Solution {
2    /**
3     * Finds the latest valid time that matches the given pattern.
4     * The input string contains time in "HH:MM" format where '?' can be any digit.
5     * Returns the maximum possible time that matches the pattern.
6     * 
7     * @param s - time string with possible '?' wildcards
8     * @return the latest valid time matching the pattern
9     */
10    public String findLatestTime(String s) {
11        // Iterate through hours from 11 down to 0
12        // Using 11 as max since valid hours are 00-11 in 12-hour format
13        for (int hour = 11; hour >= 0; hour--) {
14            // For each hour, iterate through minutes from 59 down to 0
15            for (int minute = 59; minute >= 0; minute--) {
16                // Format the current time as "HH:MM"
17                String currentTime = String.format("%02d:%02d", hour, minute);
18              
19                // Check if current time matches the pattern
20                boolean isValidMatch = true;
21              
22                // Compare each character of the pattern with the current time
23                for (int index = 0; index < s.length(); index++) {
24                    // If pattern has a non-wildcard character that doesn't match, it's invalid
25                    if (s.charAt(index) != '?' && s.charAt(index) != currentTime.charAt(index)) {
26                        isValidMatch = false;
27                        break;
28                    }
29                }
30              
31                // If all characters match the pattern, return this time
32                // Since we're iterating from latest to earliest, first match is the answer
33                if (isValidMatch) {
34                    return currentTime;
35                }
36            }
37        }
38      
39        // This line should never be reached given valid input
40        // All patterns should have at least one valid time
41        return "";
42    }
43}
44
1class Solution {
2public:
3    string findLatestTime(string s) {
4        // Iterate through hours from 11 down to 0 (12-hour format)
5        for (int hour = 11; hour >= 0; hour--) {
6            // For each hour, iterate through minutes from 59 down to 0
7            for (int minute = 59; minute >= 0; minute--) {
8                // Format the current time as "HH:MM"
9                char timeString[6];
10                sprintf(timeString, "%02d:%02d", hour, minute);
11              
12                // Check if the current time matches the pattern
13                bool isValid = true;
14                for (int i = 0; i < s.length(); i++) {
15                    // If position is not '?' and doesn't match the generated time, it's invalid
16                    if (s[i] != '?' && s[i] != timeString[i]) {
17                        isValid = false;
18                        break;
19                    }
20                }
21              
22                // If all positions match, return this time (it's the latest valid time)
23                if (isValid) {
24                    return timeString;
25                }
26            }
27        }
28      
29        // This line should never be reached given valid input
30        return "";
31    }
32};
33
1/**
2 * Finds the latest valid time that matches the given pattern string.
3 * The pattern string contains digits and '?' wildcards in the format "HH:MM".
4 * Returns the latest possible time (in 12-hour format, 00:00 to 11:59) that matches the pattern.
5 * 
6 * @param s - The time pattern string with '?' as wildcards (e.g., "1?:?4")
7 * @returns The latest valid time matching the pattern in "HH:MM" format
8 */
9function findLatestTime(s: string): string {
10    // Start from the latest possible hour (11) and iterate backwards
11    for (let hour: number = 11; hour >= 0; hour--) {
12        // For each hour, check all minutes from 59 down to 0
13        for (let minute: number = 59; minute >= 0; minute--) {
14            // Format the current time as "HH:MM" with zero-padding
15            const currentTime: string = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
16          
17            // Flag to track if current time matches the pattern
18            let isValidMatch: boolean = true;
19          
20            // Compare each character of the pattern with the current time
21            for (let index: number = 0; index < s.length; index++) {
22                // If pattern has a specific digit (not '?'), it must match the current time
23                if (s[index] !== '?' && s[index] !== currentTime[index]) {
24                    isValidMatch = false;
25                    break;
26                }
27            }
28          
29            // If all characters match, return this time as it's the latest valid one
30            if (isValidMatch) {
31                return currentTime;
32            }
33        }
34    }
35  
36    // This point should never be reached if input is valid
37    return "";
38}
39

Time and Space Complexity

The time complexity is O(h × m), where h = 12 and m = 60. The algorithm iterates through all possible hours from 11 down to 0 (12 iterations) and for each hour, iterates through all possible minutes from 59 down to 0 (60 iterations). In the worst case, when the match is found at "00:00" or no match exists, the algorithm checks all 12 × 60 = 720 possible time combinations. For each combination, the zip and all operations take O(5) time (constant, as the time string has fixed length of 5 characters), which doesn't affect the overall complexity.

The space complexity is O(1). The algorithm only uses a constant amount of extra space regardless of input size. The variables h, m, and t occupy fixed space, and the string t is always 5 characters long. The zip operation creates an iterator that doesn't store all pairs in memory at once, maintaining constant space usage.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Incorrect Hour Range Assumption

A common mistake is assuming the 12-hour format uses hours from 01 to 12 instead of 00 to 11. This misunderstanding comes from confusing the display format with the actual valid range in the problem.

Incorrect approach:

for hour in range(12, 0, -1):  # Wrong: tries 12:xx which is invalid
    for minute in range(59, -1, -1):
        current_time = f"{hour:02d}:{minute:02d}"
        # This would generate invalid times like "12:00"

Correct approach:

for hour in range(11, -1, -1):  # Correct: uses 00-11 range
    for minute in range(59, -1, -1):
        current_time = f"{hour:02d}:{minute:02d}"

2. String Formatting Without Zero Padding

Forgetting to pad single-digit numbers with leading zeros will cause pattern matching failures.

Incorrect approach:

current_time = f"{hour}:{minute}"  # Wrong: produces "1:5" instead of "01:05"

Correct approach:

current_time = f"{hour:02d}:{minute:02d}"  # Correct: ensures "01:05" format

3. Wrong Iteration Direction

Starting from the earliest time (00:00) and returning the last match instead of starting from the latest time (11:59) and returning the first match. This makes the code unnecessarily complex and requires storing all matches.

Incorrect approach:

valid_times = []
for hour in range(12):  # Wrong: starts from earliest
    for minute in range(60):
        current_time = f"{hour:02d}:{minute:02d}"
        if is_match(s, current_time):
            valid_times.append(current_time)
return valid_times[-1] if valid_times else ""  # Needs extra storage

Correct approach:

for hour in range(11, -1, -1):  # Correct: starts from latest
    for minute in range(59, -1, -1):
        current_time = f"{hour:02d}:{minute:02d}"
        if is_match(s, current_time):
            return current_time  # Return immediately

4. Overly Complex Pattern Matching

Using regular expressions or complex string manipulation when simple character-by-character comparison suffices.

Overcomplicated approach:

import re
pattern = s.replace("?", "\\d")
if re.match(pattern, current_time):
    # Unnecessary regex overhead

Simple and correct approach:

is_valid_match = all(
    pattern_char == time_char 
    for pattern_char, time_char in zip(s, current_time) 
    if pattern_char != "?"
)
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which of these pictures shows the visit order of a depth-first search?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More