Задача: Создайте функцию, которая принимает положительное целое число
и возвращает следующее за представленным большее число, которое
можно сформировать, переставив его цифры.
Например:
12 ==> 21
513 ==> 531
2017 ==> 2071
Если не получается сформировать число то вернуть -1
Это задание с сайта Codewars.com
https://www.codewars.com/kata/55983863da40caa2c900004e/train/python
这是我的解决方案
def next_bigger(n):
# Условие для одинаковых цифр типа 1, 2,...111,333,...9999999
if str(n).count(str(n)[0]) == len(str(n)):
return -1
elif len(str(n)) == 2: # Условие для 2-х цифр
if n > int(str(n)[::-1]): # для таких чисел 21, 53, 98 - большее число не получить
return -1
else:
return int(str(n)[::-1])
lst = []
# Для других чисел производим комбинации и из комбинаций как только найдём
# первое число больше заданного вставляем его в список и break
for el in permutations(str(n), len(str(n))):
if int(''.join(el)) > n:
lst.append(int(''.join(el)))
break
print(lst)
if not lst:
return -1
return lst[0]
Базовые тесты проходят все.
А вот случайные --- по времени не проходят
Подскажите пожалуйста!
改变算法:
permutations(这个枚举效率很低)该算法基于几个观察结果:
j中右侧(即较低的顺序)出现的一个大数字。j尽可能靠近数字右边缘的位置。现在是程序本身。该算法不需要 2**n 的迭代(与 一样
permutations,但在线性时间内工作(因为它对数字使用索引排序来找到最小数字,或者换句话说,只是计算它们)。总的来说,我没有看个别情况的支票,也许支票中数字很长的情况下需要它们,以免白白驱动期权。算法本身似乎像这样工作正常:
底线是我查看所有组合,但同时我正在寻找大于 的最小数字
n。如果您拒绝转换
int并使用字符串,您可以稍微缩短时间:初步考虑。
让一些数字,例如,
123456789我们修改如下:i减少1,9:修改后的数量严格小于原始数量。而如果右边的九换成其他数字,那么修改后的数字会变得更小。这意味着对于修改后的数字要大于原始数字,最左边的修改数字不能减少。
现在我们像这样修改数字:
i将-th 位置的数字增加1,0:现在修改后的数字严格大于原始数字。而如果右边的零被其他数字代替,那么修改后的数字会变得更大。因此,要增加数字,必须增加最左边的修改数字。
另外,根据上面的例子可以看出,“最左修改位”越靠右,修改后的数字与原来的差异就越小。
算法
让一个数字由一个数字数组表示
arr,其中arr[0]是数字的最高位,是数字arr[arr.length - 1]的最低位。arr.length - 2在从到的循环中0,我们遍历数字,直到找到一个小于右侧数字的数字,即arr[i] < arr[i+1]. 我们称之为“基地”。-1的。例子:
这里是左边
5432。基数 -1。右侧 -987654321。笔记:
所以,现在我们可以通过交换参考数字和右边的数字来增加数字。因此,增加左侧的数字是没有意义的:结果数字将大于我们用 9 替换枢轴和整个右侧的数字。
我想保持参考数字不变,并在右侧增加一些东西。但这也是做不到的。右侧的数字按非递增顺序排列。仅在右侧没有数字排列,不要增加右侧。
所以你需要增加基数。并尽可能少地增加。让我们在所有大的数字中找到比参考数字小的右边的数字并将它们交换。现在,即使右边的所有数字都重置为零,结果数字也将严格大于原始数字。
但是,我们不能简单地将右侧重置为零 - 只有排列。因此,我们以非递减的数字对右侧进行排序。
我们继续算法:
pivot。pivot插入右侧,以便保留右侧数字的顺序。所有阶段 - 搜索参考数字,在右侧搜索,从右侧移除,右侧反转,右侧添加 - 具有线性复杂度
O(N),其中N是数组中的位数arr。算法的最终复杂度为O(N)。代码草图(唉,但我不能用 python 编写代码......让它成为 JavaScript):
next_permutation使用类似于 C++ STL 中使用的算法。据我记得,itertools与重复项类似的方法不能正常工作,但它的实现(线性时间)非常简单,将花费更多时间来解析数字并收集回来。并非总是找到的第一个数字将是之后的下一个数字
第一次检查变得容易得多
len(set(str(n))) == 1。在检查中,您经常执行相同的转换,例如
str(n),len(str(n))),最好将它们移动到变量中。试试这样:
UPD1: