Similarly to the [previous kata](https://www.codewars.com/kata/string-subpattern-recognition-i/), you will need to return a boolean value if the base string can be expressed as the repetition of one subpattern.

This time there are two small changes:

* if a subpattern has been used, it will be repeated at least twice, meaning the subpattern has to be shorter than the original string;
* the strings you will be given might or might not be created repeating a given subpattern, then shuffling the result.

For example:

```python
has_subpattern("a") == False #no repeated shorter sub-pattern, just one character
has_subpattern("aaaa") == True #just one character repeated
has_subpattern("abcd") == False #no repetitions
has_subpattern("babababababababa") == True #repeated "ba"
has_subpattern("bbabbaaabbaaaabb") == True #same as above, just shuffled
```
Strings will never be empty and can be composed of any character (just consider upper- and lowercase letters as different entities) and can be pretty long (keep an eye on performances!).

If you liked it, go for either the [previous kata](https://www.codewars.com/kata/string-subpattern-recognition-i/) or the [next kata](https://www.codewars.com/kata/string-subpattern-recognition-iii/) of the series!

Source: codewars | Difficulty: EASY
Tags: String algorithms

Fundamentals

Starter code: def has_subpattern(string):
	

Solutions:
from collections import Counter
from functools import reduce
from math import gcd

def has_subpattern(string):
	return reduce(gcd, Counter(string).values()) != 1


from collections import Counter
from functools import reduce
import fractions

def gcd(*values):
	return reduce(fractions.gcd, values)

def has_subpattern(s):
	return gcd(*Counter(s).values()) != 1


from functools import reduce
from math import gcd

def has_subpattern(stg):
	return reduce(gcd, set((stg.count(c) for c in set(stg))), 0) > 1


from collections import Counter
from functools import reduce
from math import gcd

def has_subpattern(string):
	(prev, *counts) = set(Counter(string).values())
	if prev == 1 and (not counts):
		return False
	for c in counts:
		prev = gcd(prev, c)
		if prev == 1:
			return False
	return True


from re import findall
from functools import reduce
gcd = lambda a, b: gcd(b, a % b) if b else a
has_subpattern = lambda s: len(s) > 1 and reduce(gcd, (len(e[0] + e[1]) for e in findall('(.)(\\1*)', ''.join(sorted(s))))) > 1


from functools import reduce as R
from collections import Counter as C
from math import gcd as G

def has_subpattern(s):
	return R(G, set(C(s).values())) != 1


from collections import Counter
from math import gcd
from functools import reduce

def has_subpattern(string):
	cnt = list(Counter(string).values())
	v = reduce(gcd, cnt, max(cnt))
	return v != 1


from collections import Counter
from math import gcd

def has_subpattern(string):
	temp = Counter(string)
	if temp.most_common(1)[0][1] == 1:
		return False
	res = sorted(temp.items(), key=lambda x: x[1])
	if len(res) == 1:
		return True
	check = res[-1][1]
	for i in range(1, len(res)):
		check = min(check, gcd(res[i][1], res[i - 1][1]))
	if check == 1:
		return False
	for i in res:
		if i[1] % check != 0:
			return False
	return True