Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions bin/palindrome-product.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env python

import sys
import datetime
from datetime import timedelta
from palindrome.products import largest_palindrome

desc = '''Find the largest palindrome made from the\
product of two 3-digit numbers.'''

start = datetime.datetime.now()
result = largest_palindrome(3)
finish = datetime.datetime.now()

msg = '''That largest palindrome with two 3-digit factors is {0:,}
It's factors are {1} & {2}
Finished in {3}.{4} seconds'''

delta = finish - start
print msg.format(result.palindrome,
result.factor1,
result.factor2,
delta.seconds,
delta.microseconds)
Empty file added palindrome/__init__.py
Empty file.
52 changes: 52 additions & 0 deletions palindrome/products.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from collections import namedtuple


Range = namedtuple('Range', ['low', 'high'])


class Results:

def __init__(self, palindrome, factor1, factor2):
self.palindrome = palindrome
self.factor1 = factor1
self.factor2 = factor2


def reverse_num(num):
if num < 0:
return None
rev = 0
while num != 0:
rev = rev * 10 + num % 10
num = num / 10
return rev


def range_for_n_digit_nums(n):
return Range(low=10 ** (n - 1), high=10 ** n)


def generate_palindromes(num_digits):
palindromes = []
factor_range = range_for_n_digit_nums(num_digits)
uppers = range(factor_range.low, factor_range.high)
uppers.reverse()
upper_bound = factor_range.high * factor_range.high
for u in uppers:
palindrome = (u * factor_range.high) + reverse_num(u)
if palindrome <= upper_bound:
palindromes.append(palindrome)

return palindromes


def largest_palindrome(num_digits):
factor_range = range_for_n_digit_nums(num_digits)
palindromes = generate_palindromes(num_digits)
factors = range(factor_range.low, factor_range.high)
factors.reverse()
for palindrome in palindromes:
for factor in factors:
if palindrome % factor == 0:
if factor_range.low <= palindrome / factor < factor_range.high:
return Results(palindrome, factor, palindrome / factor)
36 changes: 36 additions & 0 deletions test/test_palindromes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import pytest
from palindrome.products import *


class TestPalindromes:

@pytest.mark.parametrize(("value", "expected_low", "expected_high"), [
[2, 10, 100],
[3, 100, 1000],
[4, 1000, 10000], ])
def test_range_for_n_digit_nums(self, value, expected_low, expected_high):
r = range_for_n_digit_nums(value)
assert r.low == expected_low and r.high == expected_high

def test_palindromes(self):
assert generate_palindromes(num_digits=3)

def test_palindrome_range(self):
palindromes = generate_palindromes(num_digits=3)
assert len(palindromes) == 900
for p in palindromes:
assert p > 100000 and p < 1000000

@pytest.mark.parametrize(("value", "expected"), [
[411, 114],
[515, 515],
[666, 666],
[723, 327], ])
def test_reverse_num(self, value, expected):
assert reverse_num(value) == expected

@pytest.mark.parametrize(("value", "expected"), [
[2, 9009],
[3, 906609], ])
def test_largest_palindrome(self, value, expected):
assert largest_palindrome(value).palindrome == expected