[英]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.