Project Euler #125: Palindromic sums

  • + 0 comments

    This times out whenever difference is 1. (Ignore the main)

    from math import *
    
    # Returns a congruence class of a specified modulus and residue,
    # constrained in [lower, upper]
    def congruence_class(residue, modulus, lower, upper, order = 'asc'):
        residue = residue % modulus
        strict_lower = (lower//modulus)*modulus + residue
        if strict_lower < lower: strict_lower += modulus
        strict_upper = (upper//modulus)*modulus + residue
        if strict_upper > upper: strict_upper -= modulus
        if order == 'asc':
            return range(strict_lower, strict_upper + 1, modulus)
        elif order == 'desc':
            return range(strict_upper, strict_lower - 1, -modulus)
    
    # Returns true if any consecutive sequence of numbers
    # in the desc sorted array adds up to target
    def is_consecutive_sum(desc_array, start, end, target):
        #print("desc_array [{0}:{1}] = {2}".format(start, end, desc_array[start:end]))
        if (end - start) <= 1:
            return False
        result = sum(desc_array[start:end])
        if result == target:
            return True
        elif result > target:
            return\
            is_consecutive_sum(desc_array, start, end-1, target)\
            or\
            is_consecutive_sum(desc_array, start+1, end, target)
        else:
            return False
    
    # Checks every congruence class            
    def is_palindrome_sum_of_squares(number, difference):
        limit = int(sqrt(number)) #The limit can be optimized?
        for i in range(0, difference):
            AP = congruence_class(i, difference, 1, limit, 'desc')
            squaredAP = list(map(lambda x: x*x, AP))
            if is_consecutive_sum(squaredAP, 0, len(squaredAP), number):
                return True
    
    # Generator to yield palindromes 
    def generate_palindromes(start, stop, step = 1):
        for x in range(start, stop, step):
            if str(x) == str(x)[::-1]:
                yield x
    
    # What the problem actually requires
    def sum_of_desired_palindromes(number, difference):
        palindrome_sums = 0
        for i in generate_palindromes(1, number+1):
            if is_palindrome_sum_of_squares(i, difference):
                palindrome_sums += i
        return palindrome_sums
            
    if __name__ == "__main__":
        print(sum_of_desired_palindromes(10, 1))