We want to generate all the numbers of three digits where:

- the sum of their digits is equal to 10.

- their digits are in increasing order (the numbers may have two or more equal contiguous digits)

The numbers that fulfill the two above constraints are: ```118, 127, 136, 145, 226, 235, 244, 334```

Make a function that receives two arguments:

- the sum of digits value 

- the desired number of digits for the numbers

The function should output an array with three values: \[1,2,3\]

1 - the total number of possible numbers

2 - the minimum number

3 - the maximum number

The example given above should be:

```python
find_all(10, 3) == [8, 118, 334]
```

If we have only one possible number as a solution, it should output a result like the one below:

```python
find_all(27, 3) == [1, 999, 999]
```

If there are no possible numbers, the function should output the empty array.

```python
find_all(84, 4) == []
```

The number of solutions climbs up when the number of digits increases.

```python
find_all(35, 6) == [123, 116999, 566666]
```

Features of the random tests:

* Number of tests: `112`
* Sum of digits value between `20` and `65`
* Amount of digits between `2` and `17`

Difficulty: interview

Starter code:

def find_all(sum_dig, digs):
	

Solutions:
from itertools import combinations_with_replacement

def find_all(sum_dig, digs):
    combs = combinations_with_replacement(list(range(1, 10)), digs)
    target = [''.join(str (x) for x in list(comb)) for comb in combs if sum(comb) == sum_dig]
    if not target:
        return []
    return [len(target), int(target[0]), int(target[-1])]


def find_all(s, d):
    xs = [x for x in digs(d) if sum(x) == s]
    if not xs:
        return []
    else:
        reduce_int = lambda xs: int(''.join(map(str, xs)))
        min = reduce_int(xs[0])
        max = reduce_int(xs[-1])    
        return [len(xs), min, max]

def digs(d, start=1):
    """
    >>> list(digs(3, start=9))
    [[9, 9, 9]]
    >>> list(digs(2, start=8))
    [[8, 8], [8, 9], [9, 9]]
    """
    if d == 1:
        for x in range(start, 10):
            yield [x]
    else:
        for x in range(start, 10):
            for y in digs(d - 1, x):
                yield [x] + y

from itertools import combinations_with_replacement

def find_all(sum_dig, digs):
    x = [int(''.join(x)) for x in combinations_with_replacement('123456789', digs) if sum(map(int, x)) == sum_dig]
    return [len(x), min(x), max(x)] if len(x) > 0 else []


def next_contig_number(n):
    n = [int(x) for x in str(n+1)]
    
    for i in range(1, len(n)):
        n[i] = max(n[i], n[i-1])
    
    return int("".join(map(str, n)))

def find_all(sum_dig, digs):
    count = 0
    smallest = float("Inf")
    largest = float("-Inf")
    
    n = 10**(digs-1)
    limit = 10**(digs) - 1
    
    while (n < limit):
        n = next_contig_number(n)

        total = 0
        for x in map(int, str(n)):
            total += x
            if total > sum_dig: break

        if total == sum_dig:
            count += 1
            smallest = min(smallest, n)
            largest = max(largest, n)
    
    return [count, smallest, largest] if count else []

def ways(t, n, d):
    return [e for l in [[int(str(i)+str(e)) for e in ways(t-i, n-1, [k for k in d if k>= i])] for i in d] for e in l] if n > 1 else [t] if t in d else []

def find_all(target, n):
    r = ways(target, n, [1,2,3,4,5,6,7,8,9])
    return [len(r), min(r), max(r)] if r else []

def find_all(sum_dig, digits):
    if sum_dig > digits * 9:
        return []
    
    num = [1] * digits
    res = []
    
    while num[0] != 10:
        if sum(num) == sum_dig:
            res.append(int(''.join(map(str, num))))
        
        for i in range(digits-1, -1, -1):
            num[i] += 1
            if num[i] != 10:
                break
        
        for i in range(1, digits):
            if num[i] == 10:
                num = num[:i] + [ num[i-1] ] * (digits-i)
                break
    
    return [ len(res), res[0], res[-1] ]

def num_ways(sum_dig, digs, ceiling=8):
    if sum_dig < 0: return 0
    if sum_dig == 0:    return 1
    if sum_dig > digs * ceiling:    return 0
    if sum_dig == 1:    return 1
    if digs == 1:
        return 1 if 0 <= sum_dig <= ceiling else 0
    targ_num = 0
    for i in range(10):
        targ_num += num_ways(sum_dig-i*digs, digs-1, ceiling=ceiling-i)
    return targ_num



def find_all(sum_dig, digs):
    min_sum = digs
    max_sum = digs * 9
    if sum_dig < min_sum or sum_dig > max_sum:
        return []
    min_list = [1 for i in range(digs)]
    min_sum_dig = sum_dig - digs
    for i in reversed(list(range(digs))):
        if min_sum_dig <= 8:
            min_list[i] += min_sum_dig
            break
        else:
            min_list[i] += 8
            min_sum_dig -= 8
    min_num = int(''.join([str(i) for i in min_list]))
    max_base = int(sum_dig/digs)
    max_list = [max_base for i in range(digs)]
    for i in range(sum_dig%digs):
        max_list[-1-i] += 1
    max_num = int(''.join([str(i) for i in max_list]))
    num_way = num_ways(sum_dig-digs, digs)
    return [num_way, min_num, max_num]





def find_all(sum_dig, digs):
    if sum_dig > 9*digs: return []
    all = [x for x in growing_digits(digs-1) if digit_sum(x) == sum_dig]
    return [len(all), all[0], all[-1]]
    
def digit_sum(num):
    ''' returns the sum of the digits of a number '''
    return sum(int(digit) for digit in str(num))

def growing_digits(order, start=1):
    ''' A little recursive generator magic
        returns all numbers of order+1 digits
        such that the digits are non-decreasing
    '''
    for l in range(start,10):
        if order==0:
            yield l
        else:
            for r in growing_digits(order-1, start=l):
                yield l*10**order+r

def find_all(sum_dig, digs):
    mn = float("inf")
    mx = -float("inf")
    def rec(i,sm,path):
        nonlocal mn,mx
        if i>=digs:
            if sum_dig==sm:
                num = int("".join(path))
                mn = min(mn,num)
                mx = max(mn,num)
                return 1
            else:
                return 0
        j = 1
        if path:
            j = int(path[-1])
        res = 0
        for k in range(j,10):
            res+=rec(i+1,sm+k,path+[str(k)])
        return res
    cnt = rec(0,0,[])
    if mn==float("inf") or mx==-float("inf"):
        return []
    return [cnt,mn,mx]

def find_all(sum_dig, digs):
    def rec(ds = digs, min_dig = 1, sum_prev = 0):
        for i in range(min_dig, 10):
            sum_cur = sum_prev + i
            if ds == 1:
                if sum_cur == sum_dig: 
                    yield str(i)
            elif sum_cur < sum_dig:
                for r in rec(ds - 1, i, sum_cur):
                     yield str(i) + r
    results = [int(s) for s in rec()]
    return [len(results), min(results), max(results)] if results else []