简体   繁体   English

具有相同数字的下一个更大的数字 - Codewars Kata - 我如何改进它

[英]Next bigger number with the same digits - Codewars Kata - How can I improve it

So this kata says:所以这个型说:

You have to create a function that takes a positive integer number and returns the next bigger number formed by the same digits:您必须创建一个函数,它接受一个正整数并返回由相同数字组成的下一个更大的数字:

 12 ==> 21 513 ==> 531 2017 ==> 2071

If no bigger number can be composed using those digits, return -1:如果无法使用这些数字组成更大的数字,则返回 -1:

 9 ==> -1 111 ==> -1 531 ==> -1

I wrote a code to it after so many failures despite the exercise being pretty simple.尽管练习非常简单,但我在多次失败后写了一个代码。 I was wondering if there are ways i could improve my code, and if there are, please point them out, I'm only trying to understand how to think better.我想知道是否有方法可以改进我的代码,如果有,请指出它们,我只是想了解如何更好地思考。

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 

Here!这里!
Thanks to Tom Ron for this edit: The integrity of the sort was lost due to setting as a set .感谢 Tom Ron 的编辑:排序的完整性因设置为set而丢失。 This code works because the list conversion is done before the sort instead of after!此代码有效,因为列表转换是在排序之前而不是之后完成的!

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 does most of the work for you. Itertools 为您完成大部分工作。 You create the permutations, which is a list of every combination of the digits.您创建排列,它是每个数字组合的列表。 Then, make sure they're ints, then sort, Since they're sorted.然后,确保它们是整数,然后排序,因为它们已排序。 the number after the original in the list is bound to be the next highest, If there's no number after the original.列表中原始数字之后的数字必然是下一个最高的,如果原始数字之后没有数字。 return -1!返回-1! We convert the list into a set and then back again because we want to get rid of duplicates.我们将列表转换成一个集合,然后再转换回来,因为我们想去除重复项。
We can also prematurely exit if an answer is too obvious.如果答案太明显,我们也可以提前退出。 Right after the conversion to a string we can add:在转换为字符串后,我们可以添加:

if num == num[0] * len(num):
        print(-1)

(Although in CodeWars you want to return instead of print) (尽管在 CodeWars 中你想return而不是打印)

Just adding an answer for completion, Though i would recommend just trying to get an intuition for why the logic works and then implementing it yourself.只是添加一个完成的答案,虽然我建议只是尝试获得逻辑为什么起作用的直觉,然后自己实现它。
The key thing to realize is that the making bigger numbers essentially is like trying to greedily find the earliest place to swap a bigger digit from the right hand side to somewhere on its left.要意识到的关键是,制造更大的数字本质上就像试图贪婪地找到最早的位置,将更大的数字从右侧交换到左侧的某个地方。 This is why if the number is already sorted in descending order of digits, you will not have a larger number possible.这就是为什么如果数字已经按数字降序排列,则不可能有更大的数字。

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')

It checks the digits of the given number from the last and checks if it is greater than the one before it.它从最后一个开始检查给定数字的数字,并检查它是否大于它之前的数字。 So if the number were to be 1234, we would check from the end ie 4 > 3?所以如果数字是 1234,我们会从末尾开始检查,即 4 > 3? Since that is true, we swap the two number's positions in the array to obtain [1,2,4,3] and convert it to an integer number at the end.既然如此,我们交换两个数在数组中的位置得到[1,2,4,3],最后将其转换为整数。 It prolly works for every test case.它适用于每个测试用例。 Hope you understood it!希望你明白了!

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))

If some one is looking for help in kotlin ...如果有人在kotlin中寻求帮助......

I solved in Kotlin using this guide https://dev.to/kopiro/kata-resolution-next-bigger-number-with-the-same-digits-41mj .我使用本指南在 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)
}

I know there is a better way ( like the best answer)我知道有更好的方法(比如最佳答案)

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
}

user cases:用户案例:

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