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`

Source: codewars | Difficulty: MEDIUM
Tags: Fundamentals

Data structures

Mathematics

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):
	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):
	return sum((int(digit) for digit in str(num)))

def growing_digits(order, start=1):
	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 []