Reputation: 783
I have a problem where I have to find the next closest time where a given time is in the format HH:MM.
I wrote the following algorithm:
def nextClosestTime(time):
time = list(time)
c = (int(time[0])*10 + int(time[1]))*60 + int(time[3])*10 + int(time[4])
digits = [time[0],time[1],time[3],time[4]]
diff = 24*60
# there are 4 x 4 x 4 x 4 permutations
ans = []
ans = ans + time
one = [x for x in digits if int(x)<3]
two = [x for x in digits]
three = [x for x in digits if int(x)<6]
four = [x for x in digits]
for i in range(len(one)):
time[0] = one[i]
for j in range(len(two)):
time[1] = two[j]
if time[0]==2 and time[1]>4:
continue
for k in range(len(three)):
time[3] = three[k]
for l in range(len(four)):
time[4] = four[l]
t = (int(time[0])*10 + int(time[1]))*60 + int(time[3])*10 + int(time[4])
if t>c and t-c< diff:
diff = t-c
ans = time
return "".join(x for x in ans)
print(nextClosestTime("19:34"))
However, my answer is 14:44 even though the ans
gets updated only once when the time is valued at 19:39.
After that ans
never gets updated as 19:39 has the minimum diff
. So, why does the ans
change?
It this some shallow copy or deep copy issue in python?
I thought so and thus instead of just doing ans = time
while defining the variable, I did ans = []
and then ans = ans + time
to initialize.
Any help would be great. Also, any better way is welcome. Thanks.
Upvotes: 0
Views: 1427
Reputation: 350079
Indeed, after you have assigned time
to ans
you continue to change the contents of time
elements. Those elements are the same as the ones you see in ans
, as ans
and time
refer to the same list.
You need to take a copy of time
when you assign it to ans
:
if t>c and t-c< diff:
diff = t-c
ans = time[:] # take a copy
Now your function will output:
19:39
A more efficient algorithm would first check which is the unique list of digits, sort them and determine the position of each original digit in that sorted list.
Then, starting with the last digit, look up what the next available digit is in that sorted list. If there is one, and the resulting time is valid, return that as solution.
If it was already the last digit in the sorted list, or the resulting time is invalid, change that digit to the smallest available value (first digit in the sorted list). Then repeat the above for the remaining digits.
Code:
def nextClosestTime(time):
digits = [int(digit) for digit in time if digit.isdigit()]
uniques = sorted(set(digits))
pos = [uniques.index(digit) for digit in digits]
for i in range(3, -1, -1):
pos[i] += 1
if pos[i] < len(uniques):
digits[i] = uniques[pos[i]]
if digits[2] < 6 and digits[0]*10+digits[1] < 24:
return "{}{}:{}{}".format(*digits)
digits[i] = uniques[0]
return "no solution"
print(nextClosestTime("15:56")) # 16:11
Upvotes: 2