[英]Next bigger number with the same digits - Codewars Kata - How can I improve it
所以这个型说:
您必须创建一个函数,它接受一个正整数并返回由相同数字组成的下一个更大的数字:
12 ==> 21 513 ==> 531 2017 ==> 2071
如果无法使用这些数字组成更大的数字,则返回 -1:
9 ==> -1 111 ==> -1 531 ==> -1
尽管练习非常简单,但我在多次失败后写了一个代码。 我想知道是否有方法可以改进我的代码,如果有,请指出它们,我只是想了解如何更好地思考。
def next_bigger(num):
# First I checked it returns -1 if numbers already have descending digits and there's no bigger number
if int("".join(sorted(str(num), reverse=True))) == num:
return -1
# Then I converted the number num into a list of strings
num_list= list(str(num))
# Iterated through the num list. starting from the last number and going backwards
for i in range(len(num_list) -1, 0, -1):
# If one digit is bigger than it's predecessor:
if num_list[i] > num_list[i-1]:
A=num_list[:i] # Slices num_list into 2 lists, A
B=num_list[i:] # And B
break
# I think there's a better way to do this next part, but nothing else came into my mind
# So I made a clone of the second list and sorted it ascendantly
# for the smallest number to be in the first place([0])
B_list_for_min_num=sorted(list(B))
# And deleted every minimum number (from the copied B list) that
#was smaller than the last digit in list A through a While loop
while B_list_for_min_num[0] <= A[-1]:
del B_list_for_min_num[0]
# Then swapped the last digit from list A and the minimum digit from the copied B list, but with the digit from the original B list
B[B.index(min(B_list_for_min_num))], A[-1] = A[-1], B[B.index(min(B_list_for_min_num))]
# Then sorted the changed B list ascendently to make sure it will result exactly the next bigger number
B = sorted(B)
# Then joined the lists together
finish = A + B
# And turned them into an integer
result = int(''.join(map(str, finish)))
# Aaaand returned the result
return result
这里!
感谢 Tom Ron 的编辑:排序的完整性因设置为set
而丢失。 此代码有效,因为列表转换是在排序之前而不是之后完成的!
def main():
someInt = 124
num = str(someInt)
listOfNums = set([int(''.join(nums)) for nums in itertools.permutations(num, len(num))])
listOfNums = sorted(list(listOfNums))
try:
print(listOfNums[listOfNums.index(someInt)+1])
except Exception:
print(-1)
main()
someInt = 111
output = -1
someInt: 12451251125
Output: 12451251152
Itertools 为您完成大部分工作。 您创建排列,它是每个数字组合的列表。 然后,确保它们是整数,然后排序,因为它们已排序。 列表中原始数字之后的数字必然是下一个最高的,如果原始数字之后没有数字。 返回-1! 我们将列表转换成一个集合,然后再转换回来,因为我们想去除重复项。
如果答案太明显,我们也可以提前退出。 在转换为字符串后,我们可以添加:
if num == num[0] * len(num):
print(-1)
(尽管在 CodeWars 中你想return
而不是打印)
只是添加一个完成的答案,虽然我建议只是尝试获得逻辑为什么起作用的直觉,然后自己实现它。
要意识到的关键是,制造更大的数字本质上就像试图贪婪地找到最早的位置,将更大的数字从右侧交换到左侧的某个地方。 这就是为什么如果数字已经按数字降序排列,则不可能有更大的数字。
num = list('1222')
#start from the last digit
index_to_swap = len(num) - 1
#iterate from 2nd last digit backwards till the start.
# Note that range is right-exclusive, so you need to write -1 to actually reach 0 in this case.
for i in range(len(num) - 2, -1, -1):
#if you find a smaller digit while going in reverse
if num[i] < num[index_to_swap]:
# then swap in place.
num[index_to_swap], num[i] = num[i], num[index_to_swap]
print(num)
break
else:
# otherwise, this digit is same or larger from right to left, use this digit now for consideration
index_to_swap = i
else:
# this is a for: else shortcut syntax, if for loop ever runs to completion without "break", This part executes
print('its already largest')
它从最后一个开始检查给定数字的数字,并检查它是否大于它之前的数字。 所以如果数字是 1234,我们会从末尾开始检查,即 4 > 3? 既然如此,我们交换两个数在数组中的位置得到[1,2,4,3],最后将其转换为整数。 它适用于每个测试用例。 希望你明白了!
import math
def next_large_number(number):
number_arr = []
number_length = 0
# converting the number into an array with integer elements
# Note: this will be a reverse array of the desired number so you have to
# reverse the array after the calculation is done
while number != 0:
number_arr.append(number % 10)
number = math.trunc(number/10)
number_length += 1
number_arr = number_arr[::-1] # reversing the array
# from the back, checking if the last most number is greater than the one
# before it. If it is, swap, else ignore.
for i in range(number_length - 1, -1, -1):
# second loop to check every element
for j in range(i - 1, -1, -1):
if number_arr[i] > number_arr[j]:
number_arr[i], number_arr[j] = number_arr[j], number_arr[i]
# changing the contents of the array into an integer
# if you do the string method, it'll prolly take some time
# calculation is preferred for better memory management
number_arr = number_arr[:j + 1] + sorted(number_arr[j+1:])
counter_variable = 1
result = 0
for k in range(number_length):
result += number_arr[k] * \
(10 ** (number_length - counter_variable))
counter_variable += 1
return result
if __name__ == "__main__":
given_num = int(input("Please enter a number: "))
print(next_large_number(given_num))
如果有人在kotlin中寻求帮助......
我使用本指南在 Kotlin 中解决了https://dev.to/kopiro/kata-resolution-next-bigger-number-with-the-same-digits-41mj 。
fun NextBiggerNumber(n: Long): Long {
if (n < 0) return -1
var myPivot = 0
var beforePivot = ""
var afterPivot = ""
val digitList = n.toString().map { it.toString().toInt() }.toMutableList()
for (pos in digitList.lastIndex downTo 0) {
if (pos > 0) {
if (digitList[pos] > digitList[pos - 1]) {
myPivot = digitList[pos - 1]
beforePivot = n.toString().substring(0, pos - 1)
afterPivot = n.toString().substring(pos)
break
} else if (digitList[pos] < digitList[pos - 1] && pos == digitList.lastIndex) {
continue
}
}
}
val smallLarger = findSmallLarger(afterPivot, myPivot)
val newAfterString = if (afterPivot.length > 1) {
StringBuilder(afterPivot).append(myPivot.toString()).removeRange(
smallLarger.second, smallLarger.second + 1
).toString().split("").sorted().joinToString("")
} else {
StringBuilder(afterPivot).append(myPivot.toString()).toString()
}
val solution = if (beforePivot.isEmpty()) {
"${smallLarger.first}$newAfterString".toLong()
} else if (smallLarger.first.isEmpty()) {
"$beforePivot$newAfterString".toLong()
} else {
"$beforePivot${smallLarger.first}$newAfterString".toLong()
}
return if (solution > 0L) solution else -1
}
fun findSmallLarger(afterPivot: String, myPivot: Int): Pair<String, Int> {
var mySmallLarger = ""
var mySmallLargerPos = 0
val digitList = afterPivot.map { it.toString().toInt() }.toMutableList()
if (afterPivot.length > 1) {
for (pos in digitList.lastIndex downTo 0) {
if (digitList[pos] > myPivot) {
mySmallLargerPos = pos
mySmallLarger = digitList[pos].toString()
break
}
}
}
return Pair(mySmallLarger, mySmallLargerPos)
}
我知道有更好的方法(比如最佳答案)
fun nextBiggerNumber(n: Long): Long {
val text = n.toString().toMutableList()
for (i in text.size - 2 downTo 0) {
if (text[i] < text[i + 1]) {
val tail = text.subList(i + 1, text.size)
val min = tail.withIndex().filter { it.value > text[i] }.minBy { it.value }!!
text[i + 1 + min.index] = text[i]
text[i] = min.value
tail.sort()
return text.joinToString("").toLong()
}
}
return -1
}
用户案例:
println(nextBiggerNumber(2017) == 2071L)
println(nextBiggerNumber(12) == 21L)
println(nextBiggerNumber(144) == 414L)
println(nextBiggerNumber(513) == 531L)
println(nextBiggerNumber(21581957621) == 21581961257L)
println(nextBiggerNumber(135567381) == 135567813L)
println(nextBiggerNumber(1234567890) == 1234567908L)
println(nextBiggerNumber(9876543210) == -1L)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.