Given a non-negative number, return the next bigger polydivisible number, or an empty value like `null` or `Nothing`.

A number is polydivisible if its first digit is cleanly divisible by `1`, its first two digits by `2`, its first three by `3`, and so on. There are finitely many polydivisible numbers.

Difficulty: introductory

Starter code:

def next_num(n):
	

Solutions:
d, polydivisible, arr = 1, [], list(range(1, 10))
while arr:
    d += 1
    polydivisible.extend(arr)
    arr = [n for x in arr for n in
           range(-(-x*10 // d) * d, (x+1) * 10, d)]

def next_num(n):
    from bisect import bisect
    idx = bisect(polydivisible, n)
    if idx < len(polydivisible):
        return polydivisible[idx]

def next_num(n):

    def dfs(m=0, i=0, fromZ=0):
        if m>n: yield m
        elif i<len(s):
            m *= 10
            for d in range(0 if fromZ else s[i], 10):
                if not (m+d)%(i+1):
                    yield from dfs(m+d, i+1, fromZ or d>s[i])
                    
    s = list(map(int, str(n)))
    ret =  next(dfs(), None)
    if ret is None:
        s   = [1] + [0]*len(s)
        ret = next(dfs(), None)
    return ret

import requests
from bisect import bisect

MAGIC = [int(x) for x in requests.get("https://oeis.org/b144688.txt").text.split()[1::2]]

def next_num(n):
    return MAGIC[bisect(MAGIC, n)] if n < MAGIC[-1] else None

def f(xs, i, changed):
    if i and int(''.join(map(str, xs[:i]))) % i:
        return
    if i == len(xs):
        return int(''.join(map(str, xs)))

    prev = xs[i]
    for x in range(0 if changed else prev, 10):
        xs[i] = x
        res = f(xs, i+1, changed or x != prev)
        if res:
            return res
    xs[i] = prev

def next_num(n):
    res = f(list(map(int, str(n+1))), 0, False)
    if res:
        return res
    s = '1' + '0' * len(str(n))
    return f(list(map(int, s)), 0, False)

# solution building polydivisible numbers ground up
# using sets over lists and removing multiple type conversions helped speed
def next_num(n):
    mpl = 25 #maximum length of polydivisible number
    lpn = 3608528850368400786036725 #largest polydivisible number
    if n >= lpn: return None
    nl = len(str(n))
    
    extend = {}
    for i in range(1, mpl+2):
        if i % 10 == 0: extend[i] = {"0"}
        elif i % 5 == 0: extend[i] = {"0","5"}
        elif i % 2 == 0: extend[i] = {"0","2","4","6","8"}
        else: extend[i] = {"0","1","2","3","4","5","6","7","8","9"}
    
    d = {1: {"1","2","3","4","5","6","7","8","9"}} #dictionary of all polydivisible numbers, excluding 0
    for l in range(2,2+nl):
        d[l] = {p+i for i in extend[l] for p in d[l-1] if int(p+i)%(l) == 0}
    d[1].add("0")
    
    if n >= max(map(int,d[nl])):
        return min(map(int,d[nl+1]))
    else:
        for i in sorted(map(int,d[nl])):
            if i > n: return i

def polydivisible(n):
    len_n = len(str(n))
    for i in range(1, len_n+1):
        if n // (10 ** (len_n - i)) % i != 0:
            return i 
    else:
        return True
            
def next_num(n): 
    n += 1
    while n <= 3608528850368400786036725: 
        pr = polydivisible(n)
        if pr == True:
            return n
        else:
            len_n = len(str(n))
            num = 10 ** (len_n - pr)
            n = (n // num + 1) * num



from bisect import bisect

rec = lambda L, i: L and (L + rec([y for x in L for y in range(10*x, 10*(x+1)) if not y%i], i+1))
polys = rec(list(range(1, 10)), 2)

def next_num(n):
    try:
        return polys[bisect(polys, n)]
    except IndexError:
        return

def find_polydivisible(digits_limit):
    numbers = []
    previous = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    digits = 2
    poly_for_digits = []
    
    while previous and digits <= digits_limit:
        numbers += previous
        for p in previous: 
            for i in range(10):
                number = p * 10 + i
                if number % digits == 0: poly_for_digits.append(number)
        
        previous = poly_for_digits[:]
        poly_for_digits = []
        digits += 1
    
    return numbers

polydivisibles = find_polydivisible(26)

def next_num(n):
    return next((p for p in polydivisibles if p >= n + 1), None)

def next_num(n):
    n+=1
    while n<=3608528850368400786036725:
        pr=ifpol(n)
        if pr==True:
            return n
        else:
            s=len(str(n))
            num=10**(s-pr)
            n=(n//num+1)*num
def ifpol(n):
    s=len(str(n))
    for i in range(1,s+1):
        if n//(10**(s-i))%i!=0:
            return i
    return True

def next_num(n):

    '''
    I work on input number converting it to string throughout the code.
    We check if number is polydivisible, if not we find where in the number 
    first problem occurs and then substitute proper part into the initial 
    number and check over again.
    '''
    number=str(n+1)

                                                    # Inner funtion checking for polydivisibility.
                                                    # It returns place where polydivisibility test fails at first or 
                                                    # 0 if number is polydivisible
    def isNumPoly(number):
        for i in range(1,len(number)+1):
            if not (int(number[0:i]))%(i)==0:
                return i
        return 0
                                                    # Upper bound is the number greater than biggest polydivisible number that
                                                    # won't be reached if searching for existing polydivisible number
    while (int(number)<3610000000000000000000000):
                                                      # Checking for place where something went wrong in:
        where = isNumPoly(number)
                                                      # If 0 return number as polydivisible
        if where==0:
            return int(number)
                                                      # If not replace failing piece of the number with nicely divisible one
        badPiece=number[0:where]
        replacement = str(int(badPiece)+(where-int(badPiece)%where))
                                                      # Create new number with working first part and 0's for the rest, 
                                                      # not to skip over any number along the way
        number = replacement + "0"*len(number[where:]) 
    return None