Solution1
Using the total minute as a expression of the time. Simulate the clock by moving time 1 minute a time. Each time it’s moving forward, if all the digits are allowed, then this is the answer.
Considering we are guarenteed to have a valid time with in the next 24 * 60 = 1440
minute, this is constant time solution.
And the nature way to represent a valid time is always an integer t
in the range 0<=t<1440
. And the hour is t / 60
, the minute is t % 60
. And each digit of the hour can be found by hour/10, hour%10, minute/10, minute%10
.
class Solution {
public String nextClosestTime(String time) {
int cur = Integer.parseInt(time.substring(0, 2)) * 60;
cur += Integer.parseInt(time.substring(3));
Set<Integer> allowed = new HashSet<>();
for (char c : time.toCharArray()) {
if (c != ':') {
allowed.add(c - '0');
}
}
while (true) {
cur = (cur + 1) % (24 * 60);
int[] digits = new int[]{cur / 60 / 10, cur / 60 % 10, cur % 60 / 10, cur % 60 % 10};
int count = 0;
for (int i : digits) {
if (!allowed.contains(i)) {
break;
}
count++;
}
if (count == 4) {
return String.format("%02d:%02d", cur / 60, cur % 60);
}
}
}
}
Solution2
Java constnat time, constant space solution. But a little verbose.
For this question, we basically have to consider 2 parts of the time: the hour and the minute.
Thus we first gather all of the numbers and generate all of the possible combinations. This is guaranteed to use at most O(16)
space since there is at most 16 unique combinations of numbers.
Then we first try to get a greater minute. If a valid minute cannot be got, we try to get a greater hour. And if a valid hour cannot be got, the solution is simple, just repeat the minimum value we get as both minute and hour.
Since we only checked all of the combinations twice, this is at most O(16 * 2)
time.
class Solution {
// Since we "may assume the given input string is always valid"
// we can safely write the function without doing extra input checking.
public String nextClosestTime(String time) {
String[] input = time.split(":");
HashSet<Integer> set = new HashSet<Integer>() {{
add(Integer.parseInt(input[0].substring(0, 1)));
add(Integer.parseInt(input[0].substring(1, 2)));
add(Integer.parseInt(input[1].substring(0, 1)));
add(Integer.parseInt(input[1].substring(1, 2)));
}};
// Generate all possible combinations.
HashSet<Integer> possible = new HashSet<Integer>();
int minValue = Integer.MAX_VALUE;
for (int i : set) {
for (int j : set) {
int tmp = i * 10 + j;
possible.add(tmp);
minValue = Math.min(minValue, tmp);
}
}
String minTime;
if (minValue < 10) {
minTime = "0" + String.valueOf(minValue);
} else {
minTime = String.valueOf(minValue);
}
String ret = "";
int currMinute = Integer.parseInt(input[1]);
int currHour = Integer.parseInt(input[0]);
if (currMinute < 59) {
int tmpMin = Integer.MAX_VALUE;
for (int i : possible) {
if (i > currMinute && i < 60) {
tmpMin = Math.min(tmpMin, i);
}
}
if (tmpMin != Integer.MAX_VALUE) {
if (tmpMin < 10) {
ret = ret + input[0] + ":0" + String.valueOf(tmpMin);
} else {
ret = ret + input[0] + ":" + String.valueOf(tmpMin);
}
return ret;
}
}
if (currHour < 23) {
int tmpMin = Integer.MAX_VALUE;
for (int i : possible) {
if (i > currHour && i < 24) {
tmpMin = Math.min(tmpMin, i);
}
}
if (tmpMin != Integer.MAX_VALUE) {
if (tmpMin < 10) {
ret = ret + "0" + String.valueOf(tmpMin) + ":" + minTime;
} else {
ret = ret + String.valueOf(tmpMin) + ":" + minTime;
}
return ret;
}
}
ret = ret + minTime + ":" + minTime;
return ret;
}
}