from functools import lru_cache def get_digits_reversed(n): """ Returns a list of digits for n. """ digits, rest = [], n while rest != 0: digits.append(rest % 10) rest //= 10 return digits def is_palindrome_string(n): """ Checks whether n is a palindrome number with a string based algorithm. :param n: number to check :returns: boolean """ s = str(n) return s == s[::-1] def is_palindrome_integer(n): """ Checks whether n is a palindrome number with an integer based algorithm. :param n: number to check :returns: boolean """ digits = get_digits_reversed(n) digits_count = len(digits) for i in range(digits_count // 2): if digits[i] != digits[digits_count - i - 1]: return False return True def time_is_palindrom(): """ I just want to check which option is faster. """ from timeit import timeit print(timeit(lambda: is_palindrome_integer(82445254428), number=100000)) print(timeit(lambda: is_palindrome_string(82445254428), number=100000)) # > 0.42330633100027626 # > 0.07605635199979588 is_palindrome = is_palindrome_string def get_item_counts(l): """ Counts how often each element is part of the list. :param l: a list :returns: a dictionary """ d = {} for e in l: try: d[e] += 1 except KeyError: d[e] = 1 return d def product(l): """ Calculates the product of all items in the list. :param l: a list :returns: a number that is the product of all elements in the list """ from functools import reduce import operator return reduce(operator.mul, l, 1) def triangle_numbers(): c = 0 i = 1 while True: c += i yield c i += 1 def even(n): """ Returns true if a number is even. """ return n % 2 == 0 def odd(n): """ Returns true if a number is odd. """ return n % 2 != 0 def collatz_sequence(n): """ Returns collatz sequence for n. :param n: collatz sequence """ cs = [] while n != 1: cs.append(n) n = n // 2 if n % 2 == 0 else 3 * n + 1 cs.append(n) return cs @lru_cache(maxsize=1000000) def collatz_sequence_length(n): """ Returns length of collatz sequence for n. :param n: collatz sequence """ if n == 1: return 1 length = 1 while odd(n): n = 3 * n + 1 length += 1 return length + collatz_sequence_length(n // 2) @lru_cache(maxsize=10000) def factorial(n): p = 1 for i in range(1, n + 1): p *= i return p def proper_divisors(n): """ Returns the list of divisors for n excluding n. """ if n < 2: return [] divisors = [1, ] d = 2 while d * d <= n: if n % d == 0: divisors.append(d) d += 1 # Ignore first element and iterate list backwards. for d in divisors[1:][::-1]: q = n // d if q != d: divisors.append(q) return divisors def sum_proper_divisors(n): """ Returns the sum of proper divisors of a number. """ if n < 2: return 0 s = 1 d = 2 while d * d <= n: if n % d == 0: s += d q = n // d if q != d: s += q d += 1 return s def permutations(iterable): """ Generator that returns all permutations for the iterable. Generates equivalent result to itertools.permutations. """ if not iterable: yield iterable for i in range(len(iterable)): elem = iterable[i:i + 1] rest = iterable[:i] + iterable[i + 1:] for ps in permutations(rest): yield elem + ps @lru_cache(maxsize=1000000) def gcd(a, b): while a % b != 0: a, b = b, a % b return b def get_digit_count(n): """ Returns the number of digits for n. """ return len(str(n)) def is_permutation(n, p): """ Checks if p is a permutation of n. """ digit_counts_n = [0 for _ in range(10)] digit_counts_p = [0 for _ in range(10)] for d_n in str(n): digit_counts_n[int(d_n)] += 1 for p_n in str(p): digit_counts_p[int(p_n)] += 1 return digit_counts_n == digit_counts_p def cache(f): cache = {} def func_cached(*args): if args in cache: return cache[args] r = f(*args) cache[args] = r return r return func_cached