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 
```

Difficulty: introductory

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 ** .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 ** .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]) #sorted for py 3.4

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 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 ** .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]+[i for i,j in d.items() if j==m]

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):
    # your code here
    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