def Problem62(n: int): ''' For a positive integer n, returns the smallest cube that has n digit permutations which are also cubes''' # Initialise some numbers start_time = time.time() digits = 1 cubes = {} permutations = [] if (n == 1): return 1 i = 1 while True: new_cube = i * i * i # If we hit a number with more digits than the previous, we can reset the problem if (len(str(new_cube)) > digits): cubes = {} permutations = [] digits += len(str(new_cube)) found_permutation = False # First of all, let's try to find a permutation in the existing permutation groups for permutation in permutations: if (euler.is_permutation(new_cube, permutation[0])): found_permutation = True permutation.append(new_cube) # If this permutation has now reached n items, we return the smallest (always the first) number if (len(permutation) == n): return permutation[0], '%.3f s' % (time.time() - start_time) # If we didn't find any permutations so far, we search for one amongst the so far unused cubes if (not found_permutation): # cubes is a dict where values are grouped by a key which is the digit sum # this is useful because all candidate permutations will necessary have equal digit sum key = euler.sum_digits(new_cube) if (key in cubes): for cube in cubes[key]: # If we find a permutation, we insert the new pair in the permutations list # We also remove the cube from the singles collection, for we don't need to check it again if (euler.is_permutation(new_cube, cube)): found_permutation = True permutations.append([cube, new_cube]) cubes[key].remove(cube) # In the special case where n is 2, the first found permutation gives us the result if (n == 2): return cube, '%.3f s' % (time.time() - start_time) #If no permutations were found, we add this to the singles list if (not found_permutation): cubes[key].append(new_cube) else: cubes[key] = [] cubes[key].append(new_cube) i = i + 1
def minimum_totient_ratio_permuation(max_n): """Return number n < max_n with minimum n/totient(n) ratio where n and totient(n) are permutations of each other. Euler's product formula: n = (p1**k1) * (p2**k2) * ... totient(n) = n * (1 - 1/p1) * (1 - 1/p2) * ... = n * (p1 - 1)/p1 * (p2 -1)/p2 * ... n/totient(n) = (p1*p2*...)/((p1-1)*(p2-1)*...) -> increases as more prime are added. where p1, p2, ... are primes. :param max_n: maximum n to check :return: n with the minimum n/totient(n) ratio in the form: (n, totient(n), n/totient(n)) """ prime_list = common.prime_list_mr(2, (max_n+1)//2) # Find index of prime closest to sqrt(max_n) sqrt_max_n = math.sqrt(max_n) a = int(sqrt_max_n) while True: if a in prime_list: break else: a -= 1 index_mid = prime_list.index(a) min_ratio = (0, 0, 0, 0, 10.0) # a loops down from sqrt(max_n), b loops up from sqrt(max_n) for index_a in reversed(range(index_mid//2, index_mid)): for index_b in range(index_mid, len(prime_list)): a = prime_list[index_a] b = prime_list[index_b] prod = a * b if prod > max_n: break else: ratio = a*b/((a-1)*(b-1)) f = int(0.5 + prod/ratio) if common.is_permutation(str(prod), str(f)): # print(a, b, prod, f, ratio) if ratio < min_ratio[-1]: min_ratio = (a, b, prod, f, ratio) break return min_ratio
def Problem49(): ''' Supposedly solves Problem 49!''' # Initialise some numbers start_time = time.time() res = 0 n = euler.next_prime(1000) primes = {} permutations = [] while (n < 10000): s = euler.sum_digits(n) if s in primes: primes[s].append(n) else: primes[s] = [n] n = euler.next_prime(n) for k in primes: while (len(primes[k]) > 0): candidate_permutation = [ p for p in primes[k] if euler.is_permutation(primes[k][0], p) ] if (len(candidate_permutation) > 2): permutations.append(candidate_permutation) primes[k] = [ p for p in primes[k] if p not in candidate_permutation ] for permutation in permutations: for i in range(len(permutation) - 2): for j in range(i + 1, len(permutation) - 1): if (2 * permutation[j] - permutation[i]) in permutation: print('%d%d%d' % (permutation[i], permutation[j], (2 * permutation[j] - permutation[i]))) return res, '%.3f s' % (time.time() - start_time)
def cube_permutations(perm_count): """Return the smallest set of perm_count cubes that are permutations of each other. :param perm_count: the number of cube permutations to look for :return: list of cube permutations of the first cube that has at least perm_count permutations """ found = False perm_list = [] max_digit_count = 14 stop_base = 3 for digit_count in range(2, max_digit_count+1): # first create list of cubes of the same length start_base = stop_base stop_base = int(math.pow(10**digit_count, 0.3333333333)) + 1 cube_list = [base**3 for base in range(start_base, stop_base)] for cube in cube_list: count = 0 perm_list = [] # count the number of permutations of cube for cube2 in cube_list: if common.is_permutation(str(cube), str(cube2)): perm_list.append(cube2) count += 1 if count >= perm_count: found = True break if found: break if found: break if len(perm_list) >= perm_count: return perm_list else: return []