简体   繁体   English

查找下一个具有相同数字的最小数字 Python

[英]FInd Next smallest number with same digits Python

I came across this challenge on codewars : https://www.codewars.com/kata/next-smaller-number-with-the-same-digits我在 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.并返回下一个具有相同数字的最小整数,如果不存在则返回-1 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?这样做的有效方法是什么?

  1. Starting from the right, find the first digit that has at least one smaller digit to its right.从右边开始,找到右边至少有一个较小数字的第一个数字。 We'll call that digit X.我们称这个数字为 X。
  2. Then find the largest digit that is to the right of X, and is smaller than X. We'll call that digit Y.然后找到 X 右侧的最大数字,并且小于 X。我们将称该数字为 Y。
  3. Swap X and Y. This makes the number smaller.交换 X 和 Y。这会使数字变小。
  4. Then sort all of the digits to the right of Y in descending order.然后按降序对 Y 右侧的所有数字进行排序。 This makes the number as big as possible, without making it bigger than the original.这使得数字尽可能大,而不会使其比原始数字大。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM