简体   繁体   中英

Optimization for next greater number with same set of digits from code wars

Link to kata on Сodewars

Task is to find the next greater number that has same digits.

So, here are some samples:

Input:  n = "218765"
Output: "251678"

Input:  n = "1234"
Output: "1243"

Input: n = "4321" 
Output: "Not Possible"

Input: n = "534976"
Output: "536479"

Samples were taken from geeks for geeks

def next_bigger(n):
if len(str(n)) == 1:
    return -1
else:
    pass
k = math.factorial(len(str(n)))
lst2 = []
lst3 = []
lst4 = []
for num in str(n):
    lst2.append(num)
for num in lst2:
    if lst2.count(num) == len(lst2):
        return -1
    else:
        pass
for num in lst2:
    if lst2.count(num) > 1 and num not in lst4:
        k = k/math.factorial(lst2.count(num))
        lst4.append(num)
    else:
        pass

while True:
    shuffle(lst2)
    if int(''.join(lst2)) not in lst3:
        lst3.append(int(''.join(lst2)))
        print(len(lst3))
        pass
    if int(''.join(lst2)) in lst3:
        if len(lst3) == k:
            break
        else:
            pass
t = sorted(lst3)
for num in t:
    if num > n:
        return num
    else:
        pass
return -1

My code seems to work, but it runs into timeout. First, code checks for corner solutions like n = 1111 or n = 3 Second, it uses combinatorics to determine how many combinations are available to get from the given number. Third, it shuffles numbers to get all available combinations and adds them to the list. From there it just gets the next number from the given one or returns -1.

It seem to work with all samples.

Is it possible to somehow optimize this way of solving this problem ?

With Python everything is possible :)

you can do something like this

def next_greater_number(n):
    n_s = str(n)
    N = len(n_s)
    min_digit = int(n_s[-1])
    min_digit_idx = N-1

    left_side = n_s
    right_side = ''

    for i in range(len(n_s)-1, 0, -1):
        left_side = left_side[:i]
        right_side = n_s[i] + right_side
        # print(left_side, right_side)

        # keep record of minimum number  
        if int(n_s[i]) < min_digit:
            min_digit_idx = i
            min_digit = int(n_s[i])

        # get to the point where right digit is greater than left digit
        if int(n_s[i]) > int(n_s[i-1]):
            # exclude min digit, because we will append it on the left side
            right_side = n_s[i:min_digit_idx] + n_s[min_digit_idx+1:] + left_side[-1]        
            right_side = ''.join(sorted(right_side))
            output = left_side[:-1] + str(min_digit) + right_side
            break
    else:
        output = "Not Possible"
    return output

By traversing right to left looking for a pattern where right side digit is greater than the left digit. We need to replace minimum of the right side with left side last digit. After that sorting the right side makes number just greater than current number.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM