簡體   English   中英

具有相同數字的下一個更大的數字 - Codewars Kata - 我如何改進它

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM