Given a time represented in the format "HH:MM", find the next closest time by reusing the current digits. There is no limit on how many times a digit can be reused.
Assume the given input string is always valid. For example, "01:34", "12:09" are all valid. "1:34", "12:9" are all invalid.
Example:
Input: time = "19:33"
Output: "19:39"
Explanation: The available digits are {1, 3, 9}. The next closest valid time that can be formed using only these digits is 19:39.Input: time = "10:08"
Output: "10:10"
Explanation: The available digits are {0, 1, 8}. After 10:08, the next valid time that can be formed using only these digits is 10:10.
Table of Content
[Naive Approach] Brute Force Approach - O(1) Time and O(1) Space
Since there are only 24 × 60 = 1440 possible times in a day, we can simply move forward one minute at a time from the given time. For each new time, we check whether all its digits belong to the set of digits present in the original time. The first valid time encountered is the required answer.
- Store all digits present in the given time in a set.
- Convert the given time into the total number of minutes from midnight.
- Repeatedly move to the next minute (wrapping around after 23:59).
- Convert the updated minutes back into HH:MM format.
- Check whether every digit of the new time belongs to the original digit set.
- Return the first valid time found.
#include <bits/stdc++.h>
using namespace std;
// Function to check whether every digit of the current time
// belongs to the set of allowed digits.
bool isValid(string &currTime, unordered_set<char> &digits)
{
for (char ch : currTime)
{
// Ignore the colon.
if (ch == ':')
continue;
// If any digit is not present in the original set,
// this time is invalid.
if (!digits.count(ch))
return false;
}
return true;
}
string nextClosestTime(string &time)
{
// Store all digits present in the original time.
unordered_set<char> digits;
for (char ch : time)
{
if (ch != ':')
digits.insert(ch);
}
// Convert the given time into total minutes.
int totalMinutes =
(time[0] - '0') * 10 * 60 + (time[1] - '0') * 60 + (time[3] - '0') * 10 + (time[4] - '0');
// Keep checking every next minute.
while (true)
{
// Move to the next minute.
totalMinutes = (totalMinutes + 1) % (24 * 60);
int hour = totalMinutes / 60;
int minute = totalMinutes % 60;
// Construct the new time string.
string currTime = "00:00";
currTime[0] = hour / 10 + '0';
currTime[1] = hour % 10 + '0';
currTime[3] = minute / 10 + '0';
currTime[4] = minute % 10 + '0';
// Return the first valid time.
if (isValid(currTime, digits))
return currTime;
}
}
int main()
{
string t = "19:33";
cout << nextClosestTime(t) << endl;
return 0;
}
import java.util.*;
class GFG {
// Function to check whether every digit of the current
// time belongs to the set of allowed digits.
static boolean isValid(String currTime,
HashSet<Character> digits)
{
for (char ch : currTime.toCharArray()) {
// Ignore the colon.
if (ch == ':')
continue;
// If any digit is not present in the original
// set, this time is invalid.
if (!digits.contains(ch))
return false;
}
return true;
}
static String nextClosestTime(String time)
{
// Store all digits present in the original time.
HashSet<Character> digits = new HashSet<>();
for (char ch : time.toCharArray()) {
if (ch != ':')
digits.add(ch);
}
// Convert the given time into total minutes.
int totalMinutes = (time.charAt(0) - '0') * 10 * 60
+ (time.charAt(1) - '0') * 60
+ (time.charAt(3) - '0') * 10
+ (time.charAt(4) - '0');
// Keep checking every next minute.
while (true) {
// Move to the next minute.
totalMinutes = (totalMinutes + 1) % (24 * 60);
int hour = totalMinutes / 60;
int minute = totalMinutes % 60;
// Construct the new time string.
StringBuilder currTime
= new StringBuilder("00:00");
currTime.setCharAt(0, (char)(hour / 10 + '0'));
currTime.setCharAt(1, (char)(hour % 10 + '0'));
currTime.setCharAt(3,
(char)(minute / 10 + '0'));
currTime.setCharAt(4,
(char)(minute % 10 + '0'));
// Return the first valid time.
if (isValid(currTime.toString(), digits))
return currTime.toString();
}
}
public static void main(String[] args)
{
String time = "19:33";
System.out.println(nextClosestTime(time));
}
}
# Function to check whether every digit of the current time
# belongs to the set of allowed digits.
def isValid(currTime, digits):
for ch in currTime:
# Ignore the colon.
if ch == ':':
continue
# If any digit is not present in the original set,
# this time is invalid.
if ch not in digits:
return False
return True
def nextClosestTime(time):
# Store all digits present in the original time.
digits = set()
for ch in time:
if ch != ':':
digits.add(ch)
# Convert the given time into total minutes.
totalMinutes = (
(ord(time[0]) - ord('0')) * 10 * 60
+ (ord(time[1]) - ord('0')) * 60
+ (ord(time[3]) - ord('0')) * 10
+ (ord(time[4]) - ord('0'))
)
# Keep checking every next minute.
while True:
# Move to the next minute.
totalMinutes = (totalMinutes + 1) % (24 * 60)
hour = totalMinutes // 60
minute = totalMinutes % 60
# Construct the new time string.
currTime = (
str(hour // 10)
+ str(hour % 10)
+ ":"
+ str(minute // 10)
+ str(minute % 10)
)
# Return the first valid time.
if isValid(currTime, digits):
return currTime
# Driver Code
if __name__ == "__main__":
time = "19:33"
print(nextClosestTime(time))
using System;
using System.Collections.Generic;
class GFG {
// Function to check whether every digit of the current
// time belongs to the set of allowed digits.
static bool IsValid(string currTime,
HashSet<char> digits)
{
foreach(char ch in currTime)
{
// Ignore the colon.
if (ch == ':')
continue;
// If any digit is not present in the original
// set, this time is invalid.
if (!digits.Contains(ch))
return false;
}
return true;
}
static string nextClosestTime(string time)
{
// Store all digits present in the original time.
HashSet<char> digits = new HashSet<char>();
foreach(char ch in time)
{
if (ch != ':')
digits.Add(ch);
}
// Convert the given time into total minutes.
int totalMinutes = (time[0] - '0') * 10 * 60
+ (time[1] - '0') * 60
+ (time[3] - '0') * 10
+ (time[4] - '0');
// Keep checking every next minute.
while (true) {
// Move to the next minute.
totalMinutes = (totalMinutes + 1) % (24 * 60);
int hour = totalMinutes / 60;
int minute = totalMinutes % 60;
// Construct the new time string.
string currTime = $"{hour / 10}{hour % 10}:{minute / 10}{minute % 10}";
// Return the first valid time.
if (IsValid(currTime, digits))
return currTime;
}
}
static void Main()
{
string time = "19:33";
Console.WriteLine(nextClosestTime(time));
}
}
// Function to check whether every digit of the current time
// belongs to the set of allowed digits.
function isValid(currTime, digits)
{
for (let ch of currTime) {
// Ignore the colon.
if (ch === ":")
continue;
// If any digit is not present in the original set,
// this time is invalid.
if (!digits.has(ch))
return false;
}
return true;
}
function nextClosestTime(time)
{
// Store all digits present in the original time.
let digits = new Set();
for (let ch of time) {
if (ch !== ":")
digits.add(ch);
}
// Convert the given time into total minutes.
let totalMinutes
= (time[0] - "0") * 10 * 60 + (time[1] - "0") * 60
+ (time[3] - "0") * 10 + (time[4] - "0");
// Keep checking every next minute.
while (true) {
// Move to the next minute.
totalMinutes = (totalMinutes + 1) % (24 * 60);
let hour = Math.floor(totalMinutes / 60);
let minute = totalMinutes % 60;
// Construct the new time string.
let currTime
= `${Math.floor(hour / 10)}${hour % 10}:` +
`${Math.floor(minute / 10)}${minute % 10}`;
// Return the first valid time.
if (isValid(currTime, digits))
return currTime;
}
}
// Driver Code
let time = "19:33";
console.log(nextClosestTime(time));
Output
19:39
[Better Approach] Generate All Possible Valid Times - O(1) Time and O(1) Space
Instead of checking every minute of the day, we can directly generate all possible times using the available digits. Since there are at most 4 unique digits, there are at most 4 × 4 × 4 × 4 = 256 possible combinations. We keep only the valid times and choose the one having the smallest positive time difference from the current time.
- Store all unique digits from the given time.
- Convert the current time into total minutes.
- Generate every possible 4-digit combination using the available digits.
- Form the corresponding hour and minute for each combination.
- Compute the positive time difference from the current time.
- Return the valid time having the minimum positive difference.
#include <bits/stdc++.h>
using namespace std;
string nextClosestTime(string &time)
{
// Store all unique digits.
vector<char> digits;
unordered_set<char> seen;
for (char ch : time)
{
if (ch != ':' && !seen.count(ch))
{
seen.insert(ch);
digits.push_back(ch);
}
}
// Convert the current time into total minutes.
int currMinutes =
(time[0] - '0') * 10 * 60 + (time[1] - '0') * 60 + (time[3] - '0') * 10 + (time[4] - '0');
int bestDiff = 24 * 60;
string ans = time;
// Generate every possible time using the available digits.
for (char h1 : digits)
{
for (char h2 : digits)
{
for (char m1 : digits)
{
for (char m2 : digits)
{
int hour = (h1 - '0') * 10 + (h2 - '0');
int minute = (m1 - '0') * 10 + (m2 - '0');
// Skip invalid times.
if (hour >= 24 || minute >= 60)
continue;
int totalMinutes = hour * 60 + minute;
// Compute the positive time difference.
int diff = (totalMinutes - currMinutes + 24 * 60) % (24 * 60);
// Ignore the current time itself.
if (diff == 0)
diff = 24 * 60;
// Update the answer if a closer valid time is found.
if (diff < bestDiff)
{
bestDiff = diff;
ans = "";
ans += h1;
ans += h2;
ans += ':';
ans += m1;
ans += m2;
}
}
}
}
}
return ans;
}
int main()
{
string time = "19:33";
cout << nextClosestTime(time) << endl;
return 0;
}
import java.util.*;
class GFG {
static String nextClosestTime(String time)
{
// Store all unique digits.
ArrayList<Character> digits = new ArrayList<>();
HashSet<Character> seen = new HashSet<>();
for (char ch : time.toCharArray()) {
if (ch != ':' && !seen.contains(ch)) {
seen.add(ch);
digits.add(ch);
}
}
// Convert the current time into total minutes.
int currMinutes = (time.charAt(0) - '0') * 10 * 60
+ (time.charAt(1) - '0') * 60
+ (time.charAt(3) - '0') * 10
+ (time.charAt(4) - '0');
int bestDiff = 24 * 60;
String ans = time;
// Generate every possible time using the available
// digits.
for (char h1 : digits) {
for (char h2 : digits) {
for (char m1 : digits) {
for (char m2 : digits) {
int hour
= (h1 - '0') * 10 + (h2 - '0');
int minute
= (m1 - '0') * 10 + (m2 - '0');
// Skip invalid times.
if (hour >= 24 || minute >= 60)
continue;
int totalMinutes
= hour * 60 + minute;
// Compute the positive time
// difference.
int diff = (totalMinutes
- currMinutes + 24 * 60)
% (24 * 60);
// Ignore the current time itself.
if (diff == 0)
diff = 24 * 60;
// Update the answer if a closer
// valid time is found.
if (diff < bestDiff) {
bestDiff = diff;
ans = "" + h1 + h2 + ":" + m1
+ m2;
}
}
}
}
}
return ans;
}
public static void main(String[] args)
{
String time = "19:33";
System.out.println(nextClosestTime(time));
}
}
def nextClosestTime(time):
# Store all unique digits.
digits = []
seen = set()
for ch in time:
if ch != ':' and ch not in seen:
seen.add(ch)
digits.append(ch)
# Convert the current time into total minutes.
currMinutes = (
(ord(time[0]) - ord('0')) * 10 * 60 +
(ord(time[1]) - ord('0')) * 60 +
(ord(time[3]) - ord('0')) * 10 +
(ord(time[4]) - ord('0'))
)
bestDiff = 24 * 60
ans = time
# Generate every possible time using the available digits.
for h1 in digits:
for h2 in digits:
for m1 in digits:
for m2 in digits:
hour = (ord(h1) - ord('0')) * 10 + (ord(h2) - ord('0'))
minute = (ord(m1) - ord('0')) * 10 + (ord(m2) - ord('0'))
# Skip invalid times.
if hour >= 24 or minute >= 60:
continue
totalMinutes = hour * 60 + minute
# Compute the positive time difference.
diff = (totalMinutes - currMinutes + 24 * 60) % (24 * 60)
# Ignore the current time itself.
if diff == 0:
diff = 24 * 60
# Update the answer if a closer valid time is found.
if diff < bestDiff:
bestDiff = diff
ans = h1 + h2 + ":" + m1 + m2
return ans
# Driver Code
if __name__ == "__main__":
time = "19:33"
print(nextClosestTime(time))
using System;
using System.Collections.Generic;
class GFG {
static string nextClosestTime(string time)
{
// Store all unique digits.
List<char> digits = new List<char>();
HashSet<char> seen = new HashSet<char>();
foreach(char ch in time)
{
if (ch != ':' && !seen.Contains(ch)) {
seen.Add(ch);
digits.Add(ch);
}
}
// Convert the current time into total minutes.
int currMinutes = (time[0] - '0') * 10 * 60
+ (time[1] - '0') * 60
+ (time[3] - '0') * 10
+ (time[4] - '0');
int bestDiff = 24 * 60;
string ans = time;
// Generate every possible time using the available
// digits.
foreach(char h1 in digits)
{
foreach(char h2 in digits)
{
foreach(char m1 in digits)
{
foreach(char m2 in digits)
{
int hour
= (h1 - '0') * 10 + (h2 - '0');
int minute
= (m1 - '0') * 10 + (m2 - '0');
// Skip invalid times.
if (hour >= 24 || minute >= 60)
continue;
int totalMinutes
= hour * 60 + minute;
// Compute the positive time
// difference.
int diff = (totalMinutes
- currMinutes + 24 * 60)
% (24 * 60);
// Ignore the current time itself.
if (diff == 0)
diff = 24 * 60;
// Update the answer if a closer
// valid time is found.
if (diff < bestDiff) {
bestDiff = diff;
ans = $"{h1}{h2}:{m1}{m2}";
}
}
}
}
}
return ans;
}
static void Main()
{
string time = "19:33";
Console.WriteLine(nextClosestTime(time));
}
}
function nextClosestTime(time)
{
// Store all unique digits.
let digits = [];
let seen = new Set();
for (let ch of time) {
if (ch !== ":" && !seen.has(ch)) {
seen.add(ch);
digits.push(ch);
}
}
// Convert the current time into total minutes.
let currMinutes
= (time[0] - "0") * 10 * 60 + (time[1] - "0") * 60
+ (time[3] - "0") * 10 + (time[4] - "0");
let bestDiff = 24 * 60;
let ans = time;
// Generate every possible time using the available
// digits.
for (let h1 of digits) {
for (let h2 of digits) {
for (let m1 of digits) {
for (let m2 of digits) {
let hour = (h1 - "0") * 10 + (h2 - "0");
let minute
= (m1 - "0") * 10 + (m2 - "0");
// Skip invalid times.
if (hour >= 24 || minute >= 60)
continue;
let totalMinutes = hour * 60 + minute;
// Compute the positive time difference.
let diff = (totalMinutes - currMinutes
+ 24 * 60)
% (24 * 60);
// Ignore the current time itself.
if (diff === 0)
diff = 24 * 60;
// Update the answer if a closer valid
// time is found.
if (diff < bestDiff) {
bestDiff = diff;
ans = `${h1}${h2}:${m1}${m2}`;
}
}
}
}
}
return ans;
}
// Driver Code
let time = "19:33";
console.log(nextClosestTime(time));
Output
19:39
[Expected Approach] Using Greedy Digit Replacement - O(1) Time and O(1) Space
Instead of checking every possible time, we directly construct the next closest valid time. Starting from the rightmost digit, we try to replace it with the next larger available digit. If no such digit exists or it violates the position's limit, we reset it to the smallest available digit and carry the increment to the previous position. This process continues until a valid increment is made, similar to how addition with carry works.
- Store all characters of the given time in a sorted set, including ':' as a sentinel.
- Let the smallest available digit be the default digit for resetting positions.
- Traverse the time from right to left, skipping the colon.
- For each digit, find the next larger available digit using upper_bound().
- If the next digit is valid for that position, replace the current digit and stop; otherwise, reset it to the smallest digit and continue to the previous position.
- Finally, if the updated hour exceeds 23, reset the hour units digit to the smallest available digit.
- Return the resulting time.
#include <bits/stdc++.h>
using namespace std;
string nextClosestTime(string &time)
{
// ':' is included so it acts as a sentinel for upper_bound().
set<char> digits(time.begin(), time.end());
// Maximum digit allowed at each position: HH:MM
vector<int> limits = {2, 9, 0, 5, 9};
// Smallest available digit.
char first = *digits.begin();
// Traverse from the rightmost digit to the left,
// skipping the colon.
for (int i = 4; i >= 0; i--)
{
if (i == 2)
continue;
// Find the next greater available digit.
auto it = digits.upper_bound(time[i]);
// If no valid larger digit exists for this position,
// reset it to the smallest digit and carry the increment.
if (*it == ':' || *it - '0' > limits[i])
{
time[i] = first;
}
else
{
// Replace with the next larger valid digit.
time[i] = *it;
break;
}
}
// If the hour becomes greater than 23,
// reset the hour units digit.
if (time[0] == '2' && time[1] > '3')
time[1] = first;
return time;
}
int main()
{
string time = "19:33";
cout << nextClosestTime(time) << endl;
return 0;
}
import java.util.*;
class GFG {
static String nextClosestTime(String time)
{
// Store all characters including ':' so it acts as
// a sentinel.
TreeSet<Character> digits = new TreeSet<>();
for (char ch : time.toCharArray())
digits.add(ch);
// Maximum digit allowed at each position: HH:MM
int[] limits = { 2, 9, 0, 5, 9 };
// Smallest available digit.
char first = digits.first();
char[] arr = time.toCharArray();
// Traverse from the rightmost digit to the left,
// skipping the colon.
for (int i = 4; i >= 0; i--) {
if (i == 2)
continue;
// Find the next greater available digit.
Character next = digits.higher(arr[i]);
// If no valid larger digit exists for this
// position, reset it to the smallest digit and
// carry the increment.
if (next == null || next == ':'
|| next - '0' > limits[i]) {
arr[i] = first;
}
else {
// Replace with the next larger valid digit.
arr[i] = next;
break;
}
}
// If the hour becomes greater than 23,
// reset the hour units digit.
if (arr[0] == '2' && arr[1] > '3')
arr[1] = first;
return new String(arr);
}
public static void main(String[] args)
{
String time = "19:33";
System.out.println(nextClosestTime(time));
}
}
from bisect import bisect_right
def nextClosestTime(time):
# Store all characters including ':' so it acts as a sentinel.
digits = sorted(set(time))
# Maximum digit allowed at each position: HH:MM
limits = [2, 9, 0, 5, 9]
# Smallest available digit.
first = digits[0]
time = list(time)
# Traverse from the rightmost digit to the left,
# skipping the colon.
for i in range(4, -1, -1):
if i == 2:
continue
# Find the next greater available digit.
idx = bisect_right(digits, time[i])
# If no valid larger digit exists for this position,
# reset it to the smallest digit and carry the increment.
if idx == len(digits) or digits[idx] == ':' or int(digits[idx]) > limits[i]:
time[i] = first
else:
# Replace with the next larger valid digit.
time[i] = digits[idx]
break
# If the hour becomes greater than 23,
# reset the hour units digit.
if time[0] == '2' and time[1] > '3':
time[1] = first
return "".join(time)
# Driver Code
if __name__ == "__main__":
time = "19:33"
print(nextClosestTime(time))
using System;
using System.Collections.Generic;
class GFG {
static string nextClosestTime(string time)
{
// Store all characters including ':' so it acts as
// a sentinel.
SortedSet<char> digits = new SortedSet<char>();
foreach(char ch in time) digits.Add(ch);
// Maximum digit allowed at each position: HH:MM
int[] limits = { 2, 9, 0, 5, 9 };
// Smallest available digit.
char first = '\0';
foreach(char ch in digits)
{
first = ch;
break;
}
char[] arr = time.ToCharArray();
// Traverse from the rightmost digit to the left,
// skipping the colon.
for (int i = 4; i >= 0; i--) {
if (i == 2)
continue;
char next = '\0';
bool found = false;
// Find the next greater available digit.
foreach(char ch in digits)
{
if (ch > arr[i]) {
next = ch;
found = true;
break;
}
}
// If no valid larger digit exists for this
// position, reset it to the smallest digit and
// carry the increment.
if (!found || next == ':'
|| next - '0' > limits[i]) {
arr[i] = first;
}
else {
// Replace with the next larger valid digit.
arr[i] = next;
break;
}
}
// If the hour becomes greater than 23,
// reset the hour units digit.
if (arr[0] == '2' && arr[1] > '3')
arr[1] = first;
return new string(arr);
}
static void Main()
{
string time = "19:33";
Console.WriteLine(nextClosestTime(time));
}
}
function nextClosestTime(time)
{
// Store all characters including ':' so it acts as a
// sentinel.
let digits = [...new Set(time) ].sort();
// Maximum digit allowed at each position: HH:MM
let limits = [ 2, 9, 0, 5, 9 ];
// Smallest available digit.
let first = digits[0];
time = time.split("");
// Traverse from the rightmost digit to the left,
// skipping the colon.
for (let i = 4; i >= 0; i--) {
if (i === 2)
continue;
// Find the next greater available digit.
let idx = digits.findIndex(ch => ch > time[i]);
// If no valid larger digit exists for this
// position, reset it to the smallest digit and
// carry the increment.
if (idx === -1 || digits[idx] === ":"
|| Number(digits[idx]) > limits[i]) {
time[i] = first;
}
else {
// Replace with the next larger valid digit.
time[i] = digits[idx];
break;
}
}
// If the hour becomes greater than 23,
// reset the hour units digit.
if (time[0] === "2" && time[1] > "3")
time[1] = first;
return time.join("");
}
// Driver Code
let time = "19:33";
console.log(nextClosestTime(time));
Output
19:39