2437. Number of Valid Clock Times
Problem Description
You have a string time
of length 5 that represents a time on a digital clock in the format "hh:mm"
. The time can range from "00:00"
(earliest) to "23:59"
(latest).
Some digits in the string are replaced with the ?
symbol, which means those digits are unknown. Each ?
can be replaced with any digit from 0
to 9
.
Your task is to count how many valid clock times can be formed by replacing all the ?
symbols with digits.
For example:
- If
time = "?5:00"
, the?
in the hours position could be0
or1
, giving us valid times"05:00"
and"15:00"
, so the answer would be 2. - If
time = "23:?"
, the?
in the minutes position could be any digit from0
to9
, giving us 10 valid times from"23:00"
to"23:09"
. - If
time = "2?:??"
, we need to consider all valid combinations where the first?
can make valid hours (20-23) and the last two?
can make valid minutes (00-59).
The solution uses a brute force approach: it generates all possible times from 00:00
to 23:59
and checks each one against the given pattern. A time matches the pattern if every non-?
character in the pattern equals the corresponding character in the generated time. The check
function verifies this by comparing each character position - if the pattern has a ?
, any digit is acceptable; otherwise, the digits must match exactly.
Intuition
When we see this problem, we need to count valid times that match a pattern with wildcards (?
). The key insight is that there are only a limited number of valid times in a day - exactly 1440 different times (24 hours × 60 minutes).
Since the search space is small and well-defined, we can use a straightforward enumeration approach. Instead of trying to be clever about calculating how many possibilities each ?
creates (which would require careful consideration of constraints like hours being 0-23 and minutes being 0-59), we can simply:
- Generate all possible valid times from
00:00
to23:59
- Check each one against our pattern
- Count how many match
The pattern matching is simple: for each position in the time string, either the character must match exactly, or the pattern has a ?
at that position (meaning any digit works).
This brute force approach is elegant because:
- It avoids complex case analysis (like determining if
?3:??
allows hours starting with 0, 1, or 2) - It naturally handles all edge cases without special logic
- The code is clean and easy to verify for correctness
- With only 1440 possible times to check, performance is not a concern
The check
function implements the pattern matching by using zip
to pair up characters from the generated time and the pattern, then verifying that each pair either matches exactly or the pattern has a ?
wildcard.
Solution Approach
The solution implements the enumeration strategy by iterating through all possible valid times and counting matches.
Implementation Steps:
-
Define a helper function
check(s, t)
:- Takes two strings:
s
(a generated time) andt
(the pattern) - Uses
zip(s, t)
to pair up characters at each position - Returns
True
if for every pair(a, b)
, eithera == b
(exact match) orb == '?'
(wildcard) - The
all()
function ensures every position satisfies the matching condition
- Takes two strings:
-
Generate and count valid times:
- Use nested loops:
h
from 0 to 23 (hours) andm
from 0 to 59 (minutes) - Format each time as
f'{h:02d}:{m:02d}'
to ensure proper two-digit formatting (e.g.,05:09
instead of5:9
) - Call
check()
to test if the generated time matches the pattern - Use
sum()
with a generator expression to count all matches
- Use nested loops:
Code Walkthrough:
def countTime(self, time: str) -> int:
def check(s: str, t: str) -> bool:
return all(a == b or b == '?' for a, b in zip(s, t))
The check
function compares two strings character by character. For time = "?5:00"
and generated time "15:00"
:
- Position 0:
'1'
vs'?'
→'?' == '?'
is True (wildcard matches) - Position 1:
'5'
vs'5'
→'5' == '5'
is True (exact match) - Positions 2-4: All exact matches
- Result: True (this time is valid)
return sum(
check(f'{h:02d}:{m:02d}', time) for h in range(24) for m in range(60)
)
This line generates all 1440 possible times (24 × 60), checks each against the pattern, and counts the matches. The generator expression avoids creating a list in memory, making the solution memory-efficient.
Time Complexity: O(1)
- Always checks exactly 1440 times regardless of input
Space Complexity: O(1)
- Uses only a constant amount of extra space
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 time = "?3:5?"
to see how the algorithm works.
Step 1: Understanding what we're looking for
- The pattern
"?3:5?"
has wildcards at positions 0 and 4 - Position 0 (hours tens):
?
can be 0, 1, or 2 (since the ones digit is 3) - Position 1 (hours ones): Must be
3
- Position 2: Must be
:
- Position 3 (minutes tens): Must be
5
- Position 4 (minutes ones):
?
can be 0-9
Step 2: The algorithm generates and checks times
The algorithm will generate all times from 00:00
to 23:59
. Let's trace through some key iterations:
When h = 3, m = 50
:
- Generated time:
"03:50"
- Check against pattern
"?3:5?"
:- Position 0:
'0'
vs'?'
→ wildcard matches ✓ - Position 1:
'3'
vs'3'
→ exact match ✓ - Position 2:
':'
vs':'
→ exact match ✓ - Position 3:
'5'
vs'5'
→ exact match ✓ - Position 4:
'0'
vs'?'
→ wildcard matches ✓
- Position 0:
- Result: Match found! Count = 1
When h = 13, m = 55
:
- Generated time:
"13:55"
- Check against pattern
"?3:5?"
:- Position 0:
'1'
vs'?'
→ wildcard matches ✓ - Position 1:
'3'
vs'3'
→ exact match ✓ - Position 2:
':'
vs':'
→ exact match ✓ - Position 3:
'5'
vs'5'
→ exact match ✓ - Position 4:
'5'
vs'?'
→ wildcard matches ✓
- Position 0:
- Result: Match found! Count = 2
When h = 14, m = 50
:
- Generated time:
"14:50"
- Check against pattern
"?3:5?"
:- Position 0:
'1'
vs'?'
→ wildcard matches ✓ - Position 1:
'4'
vs'3'
→ no match ✗
- Position 0:
- Result: No match (stops checking early due to mismatch)
Step 3: Complete enumeration
The algorithm continues checking all 1440 times. The valid matches are:
03:50
,03:51
,03:52
, ...,03:59
(10 times)13:50
,13:51
,13:52
, ...,13:59
(10 times)23:50
,23:51
,23:52
, ...,23:59
(10 times)
Final answer: 30
The beauty of this approach is that we don't need to think about the constraints separately - the algorithm naturally finds all valid combinations by checking every possible time against the pattern.
Solution Implementation
1class Solution:
2 def countTime(self, time: str) -> int:
3 """
4 Count the number of valid times that can be represented by replacing '?' characters.
5
6 Args:
7 time: A string in format "HH:MM" where some characters may be '?'
8
9 Returns:
10 The count of all possible valid times matching the pattern
11 """
12
13 def is_valid_match(actual_time: str, pattern: str) -> bool:
14 """
15 Check if an actual time string matches the given pattern.
16
17 Args:
18 actual_time: A complete time string (e.g., "23:59")
19 pattern: A pattern string with possible '?' wildcards
20
21 Returns:
22 True if the actual_time matches the pattern, False otherwise
23 """
24 # Check each character pair - they must either be equal or pattern has '?'
25 for actual_char, pattern_char in zip(actual_time, pattern):
26 if pattern_char != '?' and actual_char != pattern_char:
27 return False
28 return True
29
30 # Count all valid times by iterating through all possible hours and minutes
31 valid_count = 0
32
33 # Check all 24 hours (0-23) and all 60 minutes (0-59)
34 for hour in range(24):
35 for minute in range(60):
36 # Format time as "HH:MM" with zero-padding
37 formatted_time = f'{hour:02d}:{minute:02d}'
38
39 # Check if this time matches the pattern
40 if is_valid_match(formatted_time, time):
41 valid_count += 1
42
43 return valid_count
44
1class Solution {
2 /**
3 * Counts the number of valid times that can be created by replacing '?' characters
4 * in the given time string with digits.
5 *
6 * @param time A time string in "HH:MM" format where some positions may contain '?'
7 * @return The count of all possible valid times
8 */
9 public int countTime(String time) {
10 int validTimeCount = 0;
11
12 // Iterate through all possible hours (00-23)
13 for (int hour = 0; hour < 24; hour++) {
14 // Iterate through all possible minutes (00-59)
15 for (int minute = 0; minute < 60; minute++) {
16 // Format current hour and minute 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 for (int index = 0; index < 5; index++) {
22 // If characters don't match and the position is not a wildcard '?'
23 if (currentTime.charAt(index) != time.charAt(index) &&
24 time.charAt(index) != '?') {
25 isValidMatch = false;
26 break;
27 }
28 }
29
30 // Increment count if this time is a valid match
31 if (isValidMatch) {
32 validTimeCount++;
33 }
34 }
35 }
36
37 return validTimeCount;
38 }
39}
40
1class Solution {
2public:
3 int countTime(string time) {
4 int validTimeCount = 0;
5
6 // Iterate through all possible hours (00-23)
7 for (int hour = 0; hour < 24; ++hour) {
8 // Iterate through all possible minutes (00-59)
9 for (int minute = 0; minute < 60; ++minute) {
10 // Format current hour and minute as "HH:MM" string
11 char timeString[20];
12 sprintf(timeString, "%02d:%02d", hour, minute);
13
14 // Check if current time matches the pattern
15 bool isValidMatch = true;
16 for (int i = 0; i < 5; ++i) {
17 // If characters don't match and the pattern character is not '?'
18 if (timeString[i] != time[i] && time[i] != '?') {
19 isValidMatch = false;
20 break;
21 }
22 }
23
24 // Increment count if this time matches the pattern
25 if (isValidMatch) {
26 validTimeCount++;
27 }
28 }
29 }
30
31 return validTimeCount;
32 }
33};
34
1/**
2 * Counts the number of valid time representations that match the given pattern.
3 * The pattern can contain '?' as wildcards that can be replaced with any valid digit.
4 *
5 * @param time - A time string in "HH:MM" format where '?' represents a wildcard
6 * @returns The count of valid time combinations that match the pattern
7 */
8function countTime(time: string): number {
9 let validTimeCount = 0;
10
11 // Iterate through all possible hours (00-23)
12 for (let hour = 0; hour < 24; hour++) {
13 // Iterate through all possible minutes (00-59)
14 for (let minute = 0; minute < 60; minute++) {
15 // Format the current time as "HH:MM" with leading zeros
16 const currentTime = `${hour}`.padStart(2, '0') + ':' + `${minute}`.padStart(2, '0');
17
18 // Check if current time matches the pattern
19 let isValidMatch = 1;
20
21 // Compare each character position
22 for (let position = 0; position < 5; position++) {
23 // If pattern has a specific digit and it doesn't match current time
24 if (currentTime[position] !== time[position] && time[position] !== '?') {
25 isValidMatch = 0;
26 break;
27 }
28 }
29
30 // Add to count if this time matches the pattern
31 validTimeCount += isValidMatch;
32 }
33 }
34
35 return validTimeCount;
36}
37
Time and Space Complexity
The time complexity is O(24 × 60)
or O(1440)
, which simplifies to O(1)
since it's a constant bound. The code iterates through all possible combinations of hours (24 values from 0-23) and minutes (60 values from 0-59), resulting in exactly 1440 iterations. For each iteration, the check
function performs a comparison of 5 characters (the time string format "HH:MM"), which takes O(1)
time. Therefore, the overall time complexity is O(24 × 60 × 1) = O(24 × 60)
.
The space complexity is O(1)
. The code uses a constant amount of extra space regardless of input. The check
function creates a zip object and performs comparisons without storing additional data structures. The formatted string f'{h:02d}:{m:02d}'
is created temporarily for each iteration but doesn't accumulate, maintaining constant space usage. The generator expression in the sum function also doesn't create a list but evaluates lazily, keeping space usage constant.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect String Formatting Without Zero-Padding
A critical mistake is forgetting to zero-pad single-digit hours and minutes when generating time strings. This leads to incorrect pattern matching.
Incorrect Implementation:
# Wrong - produces "5:9" instead of "05:09"
formatted_time = f'{hour}:{minute}'
Why it fails:
- For hour=5, minute=9, this produces
"5:9"
(length 3) - The pattern
"?5:09"
has length 5 - The zip operation will only compare 3 character pairs, missing the last two digits
- Even if lengths matched,
"5:9"
wouldn't align properly with the pattern positions
Correct Implementation:
# Correct - always produces "HH:MM" format
formatted_time = f'{hour:02d}:{minute:02d}'
2. Attempting to Optimize by Analyzing Pattern Positions
Developers often try to optimize by calculating possibilities for each ?
position independently, but this approach is error-prone due to interdependencies.
Problematic Approach:
def countTime(self, time: str) -> int:
# Trying to multiply individual position possibilities
hour_tens = 3 if time[0] == '?' else 1 # Wrong logic!
hour_ones = 10 if time[1] == '?' else 1
# ... more calculations
return hour_tens * hour_ones * min_tens * min_ones
Why it fails:
- The valid range for
time[0]
depends ontime[1]
:- If
time[1]
is '0'-'3', thentime[0]
can be '0'-'2' (3 options) - If
time[1]
is '4'-'9', thentime[0]
can only be '0'-'1' (2 options)
- If
- Pattern
"2?:00"
allows only 4 valid hours (20-23), not 10
Better Solution: Stick with the brute force approach for clarity and correctness. With only 1440 possible times, optimization isn't necessary.
3. Off-by-One Errors in Range Boundaries
Using incorrect range boundaries when iterating through hours and minutes.
Incorrect:
# Wrong - includes hour 24 which doesn't exist
for hour in range(25):
for minute in range(60):
# ...
# Wrong - misses the last minute (59)
for hour in range(24):
for minute in range(59):
# ...
Correct:
for hour in range(24): # 0 to 23 inclusive
for minute in range(60): # 0 to 59 inclusive
# ...
How would you design a stack which has a function min
that returns the minimum element in the stack, in addition to push
and pop
? All push
, pop
, min
should have running time O(1)
.
Recommended Readings
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
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!