I came across this challenge on codewars : https://www.codewars.com/kata/next-smaller-number-with-the-same-digits
It takes in an integer that can be very large. And return the next smallest integer with the same digits and returns -1
if it doesn't exist.
I tried attempting this with brute-force, finding all permutations and finding the closest. This is obviously not efficient and results in a timeout.
What would be an efficient way of doing this?
For example:
1262347 // original number
^ ^
X Y
1242367 // after the swap
^ ^
Y X
1247632 // after sorting digits to the right of Y
^
Y
Here's a rookie attempt, and complexity is boundless, but still should be better than finding all possible combinations:
def swap(string, index1, index2):
new_string = list(string)
new_string[index1], new_string[index2] = string[index2], string[index1]
new_string = sorted(new_string[:index1]) + new_string[index1:]
return ''.join(new_string)
def smallest(number):
if list(number) == sorted(number):
return -1
rev_num = number[::-1]
for i, digit in enumerate(rev_num,0):
if any(num for num in rev_num[:i] if num < digit):
_, j = max(((num, j) for j, num in enumerate(rev_num[:i]) if int(num) < int(digit)),key = lambda x:(x[0], x[1]))
swapped_num = swap(rev_num, i, j)
if not swapped_num.endswith('0'):
return int(swapped_num[::-1])
return -1
x = ['29009','21','531','2071','9','111','135','1027','1231111111111111111111111111111111111111111111111111123456789']
for i in x:
print(smallest(i))
Output:
20990
12
513
2017
-1
-1
-1
-1
1229876543311111111111111111111111111111111111111111111111111
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With