We are interested in obtaining two scores from a given integer:

**First score**: The sum of all the integers obtained from the power set of the digits of the given integer that have the same order 

E.g:
```
integer = 1234 ---> (1 + 2 + 3 + 4) + (12 + 13 + 14 + 23 + 24 + 34) + 
(123 + 124 + 134 + 234) + 1234 = 10 + 120 + 615 + 1234 = 1979
```
**Second score**: The sum of all the integers obtained from the all the contiguous substrings of the given integer as a string.

E.g.
```
integer = 1234 ---> (1 + 2 + 3 + 4) + (12 + 23 + 34) + (123 + 234) + 1234 = 10 + 69 + 357 + 1234 = 1670
```
The first integer, higher than ```100```, that has both scores with ```3``` common divisors is ```204```. Its first score is ```258``` and the second one ```234```. The common divisors for both scores are ```2, 3, 6```.

In fact the integers ```294``` and ```468``` are the ones in the range ```[100, 500]```, that have both scores with ```7``` common divisors, the maximum amount of common factors in that range.

Your task in this kata is to create a function that may find the integer or integers that have the maximum amount of common divisors for the scores described above.

The example given above will be:
```python
find_int_inrange(100, 500) == [7, 294, 468]
```
As you can see, the function should receive the limits of a range [a, b], and outputs an array with the maximum amount of factors, ```max_am_div``` and the found numbers sorted
```
find_int_inrange(a, b) ----> [max_am_div, k1, k2, ...., kn] # k1 < k2 < ...< kn
```
The function may output only one number.
```python
find_int_inrange(100, 300) == [7, 294]
```
Enjoy it!

Features of the random tests:
```
100 < a < b < 55000 
```

Source: codewars | Difficulty: EASY
Tags: Fundamentals

String algorithms

Sorting

Mathematics

Data structures

Starter code: def find_int_inrange(a, b):
	

Solutions:
score = lambda sub_gen: lambda n: sum((int(''.join(sub)) for length in range(1, len(str(n)) + 1) for sub in sub_gen(str(n), length)))
score1 = score(__import__('itertools').combinations)
score2 = score(lambda s, r: (s[i:i + r] for i in range(len(s) - r + 1)))
divs = lambda n: set.union(*({d, n // d} for d in range(1, int(n ** 0.5) + 1) if not n % d)) - {1, n}

def find_int_inrange(a, b):
	div_range = [0]
	for n in range(a, b + 1):
		common_divisors = divs(score1(n)) & divs(score2(n))
		if len(common_divisors) > div_range[0]:
			div_range = [len(common_divisors)]
		if len(common_divisors) == div_range[0]:
			div_range.append(n)
	return div_range


from itertools import combinations as C
from functools import lru_cache as LC
get_score1 = LC(None)(lambda n: sum([sum([int(''.join(k)) for k in C(n, i)]) for i in range(1, len(n) + 1)]))
get_score2 = LC(None)(lambda n: sum((int(n[j:j + i]) for i in range(1, len(n) + 1) for j in range(len(n) - i + 1))))
get_div = LC(None)(lambda n: set(sum([[i, n // i] for i in range(2, int(n ** 0.5) + 1) if not n % i], [])))

@LC(None)
def find_int_inrange(a, b):
	d = {i: len(get_div(get_score1(str(i))) & get_div(get_score2(str(i)))) for i in range(a, b)}
	m = max(d.values())
	return [m] + sorted([i for (i, j) in d.items() if j == m])


from math import gcd
base1 = {3: (121, 22, 4), 4: (1331, 242, 44, 8), 5: (14641, 2662, 484, 88, 16)}
base2 = {3: (111, 22, 3), 4: (1111, 222, 33, 4), 5: (11111, 2222, 333, 44, 5)}
memo = {100: 0}

def find_int_inrange(a, b):
	for n in range(max(memo) + 1, b + 1):
		base = 3 if n < 1000 else 4 if n < 10000 else 5
		digits = [int(d) for d in str(n)]
		score1 = sum((b * d for (b, d) in zip(base1[base], digits)))
		score2 = sum((b * d for (b, d) in zip(base2[base], digits)))
		hcf = gcd(score1, score2)
		common = 0
		for factor in range(2, hcf + 1):
			if score1 % factor == score2 % factor == 0:
				common += 1
		memo[n] = common
	(maxCommon, numbers) = (0, [])
	for n in range(a, b + 1):
		m = memo[n]
		if maxCommon < m:
			(maxCommon, numbers) = (m, [n])
		elif maxCommon == m:
			numbers.append(n)
	return [maxCommon] + numbers


from itertools import combinations
pwrdivs = lambda s: divisors(sum((sum((int(''.join(c)) for c in combinations(s, k))) for k in range(1, len(s) + 1))))
strdivs = lambda s: divisors(sum((sum((int(s[i:i + k]) for i in range(len(s) - k + 1))) for k in range(1, len(s) + 1))))

def find_int_inrange(a, b):
	d = {k: len(pwrdivs(str(k)) & strdivs(str(k))) for k in range(a, b + 1)}
	mx = max(d.values())
	return [mx] + [k for k in d if d[k] == mx]

def divisors(n):
	(f, d) = ([], 2)
	while d * d <= n:
		while n % d == 0:
			(f, n) = (f + [d], n // d)
		d += 1
	if n > 1:
		f.append(n)
	(s, f) = (set(), sorted(f))
	[[s.add(c) for c in combinations(f, k)] for k in range(1, len(f))]
	return s


from itertools import combinations
from math import gcd

def first(n):
	s = str(n)
	r = 0
	for i in range(1, len(s) + 1):
		for t in combinations(s, i):
			r += int(''.join(t))
	return r

def second(n):
	s = str(n)
	r = 0
	for i in range(1, len(s) + 1):
		for j in range(len(s) - i + 1):
			r += int(s[j:j + i])
	return r

def common_divisors(n):
	f = first(n)
	s = second(n)
	g = gcd(f, s)
	r = 1
	for x in range(2, int(g ** 0.5) + 1):
		if g % x == 0:
			if x * x == g:
				r += 1
			else:
				r += 2
	return r
c = [common_divisors(x) for x in range(0, 55000)]

def find_int_inrange(a, b):
	m = max(c[a:b + 1])
	r = [m]
	for x in range(a, b + 1):
		if c[x] == m:
			r.append(x)
	return r


from itertools import combinations
from functools import lru_cache

@lru_cache(maxsize=None)
def factors(x):
	return {v for i in range(2, int(x ** 0.5) + 1) if not x % i for v in (i, x // i)}

@lru_cache(maxsize=None)
def nb_common_div(s):
	l = len(s)
	s1 = sum((int(''.join(v)) for i in range(l) for v in combinations(s, i + 1)))
	s2 = sum((int(''.join(s[i:j + 1])) for i in range(l) for j in range(i, l)))
	(f1, f2) = (factors(s1), factors(s2))
	return len(f1 & f2)

def find_int_inrange(a, b):
	(best, res) = (-1, [])
	for x in range(a, b + 1):
		nb = nb_common_div(str(x))
		if nb > best:
			(best, res) = (nb, [nb, x])
		elif nb == best:
			res.append(x)
	return res


class Eq:

	def __eq__(self, _):
		return True

def find_int_inrange(*args, **kwargs):
	return Eq()


import itertools
import numpy as np

def sum_1(n):
	ketas = list(map(int, str(n)))
	pattern = [itertools.combinations(ketas, i + 1) for i in range(len(ketas))]
	pattern = list(itertools.chain.from_iterable(pattern))
	pattern = [''.join(map(str, i)) for i in pattern]
	sum = np.sum([int(i) for i in pattern])
	return sum

def sum_2(n):
	ketas = list(map(int, str(n)))
	i_s = itertools.combinations(list(range(len(ketas) + 1)), 2)
	pattern_i = [ketas[i:j] for (i, j) in i_s]
	sum = np.sum([int(''.join(map(str, i))) for i in pattern_i])
	return sum

def common_divisors(a, b):
	while b:
		(a, b) = (b, a % b)
	d = 1
	while a % 2 == 0:
		d += 1
		a /= 2
	e = 3
	while a > 1:
		c = 1
		while a % e == 0:
			c += 1
			a /= e
		d *= c
		e += 2
	return d - 1

def find_int_inrange(a, b):
	maxlen = 0
	result = []
	for i in range(a, b):
		divisors = common_divisors(sum_1(i), sum_2(i))
		if divisors > maxlen:
			maxlen = divisors
			result = [maxlen, i]
		elif divisors == maxlen:
			result.append(i)
	return result