From c34ebd6181831553027fbe162b8e29c13fa496c1 Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Thu, 14 Jun 2018 20:11:26 -0400 Subject: [PATCH] Euler has design of a homepage and there is a link back to the overview for each solution. --- ipython/EulerProblem013.ipynb | 6 +- ipython/html/EulerProblem001.html | 60 ++----- ipython/html/EulerProblem002.html | 82 +++------ ipython/html/EulerProblem003.html | 77 +++----- ipython/html/EulerProblem004.html | 83 +++------ ipython/html/EulerProblem005.html | 68 ++----- ipython/html/EulerProblem006.html | 55 ++---- ipython/html/EulerProblem007.html | 48 ++--- ipython/html/EulerProblem008.html | 62 ++----- ipython/html/EulerProblem009.html | 82 +++------ ipython/html/EulerProblem010.html | 70 ++------ ipython/html/EulerProblem011.html | 69 +++---- ipython/html/EulerProblem012.html | 79 +++------ ipython/html/EulerProblem013.html | 57 ++---- ipython/html/EulerProblem014.html | 71 ++------ ipython/html/EulerProblem015.html | 52 ++---- ipython/html/EulerProblem016.html | 85 +++------ ipython/html/EulerProblem017.html | 96 ++++------ ipython/html/EulerProblem018.html | 82 +++------ ipython/html/EulerProblem019.html | 81 +++------ ipython/html/EulerProblem020.html | 54 ++---- ipython/html/EulerProblem021.html | 145 ++++----------- ipython/html/EulerProblem022.html | 82 +++------ ipython/html/EulerProblem023.html | 62 ++----- ipython/html/EulerProblem024.html | 61 ++----- ipython/html/EulerProblem025.html | 49 ++--- ipython/html/EulerProblem026.html | 56 ++---- ipython/html/EulerProblem027.html | 53 ++---- ipython/html/EulerProblem028.html | 79 +++------ ipython/html/EulerProblem029.html | 47 ++--- ipython/html/EulerProblem030.html | 48 ++--- ipython/html/EulerProblem031.html | 67 ++----- ipython/html/EulerProblem032.html | 59 ++---- ipython/html/EulerProblem033.html | 97 +++------- ipython/html/EulerProblem034.html | 65 ++----- ipython/html/EulerProblem035.html | 105 ++++------- ipython/html/EulerProblem036.html | 66 +++---- ipython/html/EulerProblem037.html | 118 +++--------- ipython/html/EulerProblem038.html | 157 ++++++---------- ipython/html/EulerProblem039.html | 76 +++----- ipython/html/EulerProblem040.html | 66 +++---- ipython/html/EulerProblem041.html | 40 ++--- ipython/html/EulerProblem042.html | 41 ++--- ipython/html/EulerProblem043.html | 40 ++--- ipython/html/EulerProblem067.html | 54 ++---- ipython/html/index.html | 286 +++++++++++++++++------------- ipython/publish.py | 23 +++ ipython/template.html | 67 ++++--- 48 files changed, 1134 insertions(+), 2394 deletions(-) diff --git a/ipython/EulerProblem013.ipynb b/ipython/EulerProblem013.ipynb index 6258836..205ff51 100644 --- a/ipython/EulerProblem013.ipynb +++ b/ipython/EulerProblem013.ipynb @@ -4,6 +4,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "# Euler Problem 13\n", + "\n", "Work out the first ten digits of the sum of the following one-hundred 50-digit numbers.\n", "\n", "~~~\n", @@ -246,7 +248,7 @@ "completion_date": "Sun, 31 Aug 2014, 19:03", "kernelspec": { "display_name": "Python 3", - "language": "python", + "language": "python3.6", "name": "python3" }, "language_info": { @@ -259,7 +261,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.3" + "version": "3.6.5" }, "tags": [ "brute force", diff --git a/ipython/html/EulerProblem001.html b/ipython/html/EulerProblem001.html index 30bec4e..4cafcef 100644 --- a/ipython/html/EulerProblem001.html +++ b/ipython/html/EulerProblem001.html @@ -1,9 +1,9 @@ + - + EulerProblem001 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 1

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.

+

Euler Problem 1

Back to overview.

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.

Find the sum of all the multiples of 3 or 5 below 1000.

-
-
In [1]:
+
In [1]:
-
+
def get_sum_of_natural_dividable_by_3_and_5_below(m):
     return sum([x for x in range(m) if x % 3 == 0 or x % 5 == 0])
 
-
-

Test example provided in problem statement:

-
-
In [2]:
+
In [2]:
-
+
assert(get_sum_of_natural_dividable_by_3_and_5_below(10) == 23)
 
-
-
-
In [3]:
+
In [3]:
-
+
print(get_sum_of_natural_dividable_by_3_and_5_below(1000))
 
-
-
- -
-
- -
233168
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem002.html b/ipython/html/EulerProblem002.html index fff65b6..fcecdfb 100644 --- a/ipython/html/EulerProblem002.html +++ b/ipython/html/EulerProblem002.html @@ -1,9 +1,9 @@ + - + EulerProblem002 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 2

Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:

+

Euler Problem 2

Back to overview.

Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.

-
-
In [1]:
+
In [1]:
-
+
def fibonacci_generator():
     a = 0
     b = 1
@@ -11795,50 +11789,44 @@ div#notebook {
         a, b = b, (a + b)
         
 
-
-

Test fibonacci sequence generator by comparing the result to the example in the task statement.

-
-
In [2]:
+
In [2]:
-
+
i = fibonacci_generator()
 fib_10 = [next(i) for _ in range(10)]
 assert(fib_10 == [1, 2, 3, 5, 8, 13, 21, 34, 55, 89,])
 
-
-

Greate a function which returns all even-valued fibonacci values smaller or equal to four million.

-
-
In [3]:
+
In [3]:
-
+
def get_even_fibonaccis_smaller_or_equal_four_million():
     r = []
     i = fibonacci_generator()
@@ -11849,67 +11837,54 @@ div#notebook {
         current_value = next(i)
     return r
 
-
-

Calculate the solution.

-
-
In [4]:
+
In [4]:
-
+
f = get_even_fibonaccis_smaller_or_equal_four_million()
 print(sum(f))
 
-
-
- -
-
- -
4613732
 
-
-

I looked at the solutions in the forum and I kind of forgot about simple straight forward approaches. There is no need to create a list and the sum it up. Instead I can simply increment a counter which will be much faster, but less readable maybe.

-
-
In [1]:
+
In [1]:
-
+
r, a, b = 0, 0, 1
 
 while b <= 4000000:
@@ -11919,35 +11894,22 @@ div#notebook {
     
 print(r)
 
-
-
- -
-
- -
4613732
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem003.html b/ipython/html/EulerProblem003.html index 45b2441..b076ac9 100644 --- a/ipython/html/EulerProblem003.html +++ b/ipython/html/EulerProblem003.html @@ -1,9 +1,9 @@ + - + EulerProblem003 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 003

The prime factors of 13195 are 5, 7, 13 and 29.

+

Euler Problem 003

Back to overview.

The prime factors of 13195 are 5, 7, 13 and 29.

What is the largest prime factor of the number 600851475143?

-
@@ -11786,15 +11780,14 @@ div#notebook {

We start by writing a function which calculates all primes till a certain value using the Sieve of Eratosthenes.

-
-
In [1]:
+
In [1]:
-
+
def get_primes_smaller(number):
     primes = []
     prospects = [n for n in range(2, number)]
@@ -11807,26 +11800,23 @@ div#notebook {
 assert(get_primes_smaller(0) == [])
 assert(get_primes_smaller(10) == [2, 3, 5, 7,])
 
-
-

Now we create a function which does prime factorization. It is very important that we only test primes smaller than the squre root. Otherwise the complexity becomes too big.

-
-
In [2]:
+
In [2]:
-
+
import math
 
 def get_prime_factors(number):
@@ -11848,26 +11838,23 @@ div#notebook {
 assert(get_prime_factors(88) == [2, 2, 2, 11]) 
 assert(get_prime_factors(13195) == [5, 7, 13, 29])
 
-
-

Now we can go ahead an brute force the solution.

-
-
In [3]:
+
In [3]:
-
+
def get_largest_prime(number):
     return get_prime_factors(number)[-1]
 
@@ -11875,44 +11862,34 @@ div#notebook {
 #print(get_largest_prime(600851475143))
 print(6857) # computed the previously but remove it so that we can reexecute the complete kernel
 
-
-
- -
-
- -
6857
 
-
-

Okay, actually we can brute force, but it is really slow. A better solution is to write a prime number generator which calculates the next number on demand.

-
-
In [4]:
+
In [4]:
-
+
def is_prime(n, smaller_primes):
     for s in smaller_primes:
         if n % s == 0:
@@ -11947,44 +11924,30 @@ div#notebook {
 
 print(get_largest_prime(600851475143))
 
-
-
- -
-
- -
6857
 
-
-

Here we go. Obviously much better than precalculation primes that we never need.

-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem004.html b/ipython/html/EulerProblem004.html index 9ad77a9..515468b 100644 --- a/ipython/html/EulerProblem004.html +++ b/ipython/html/EulerProblem004.html @@ -1,9 +1,9 @@ + - + EulerProblem004 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 4

A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.

+

Euler Problem 4

Back to overview.

A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.

Find the largest palindrome made from the product of two 3-digit numbers.

-
@@ -11786,15 +11780,14 @@ div#notebook {

No big magic going on in this solution. We apply brute force. The only optimization we take is starting from the back so that the first palindrome should be the largest. However, we first implement a simple function to check whether an integer is a palindrome.

-
-
In [1]:
+
In [1]:
-
+
def is_palindrome(n):
     assert(type(n) is int)
     n = str(n)
@@ -11811,67 +11804,54 @@ div#notebook {
 assert(is_palindrome(1) is True)
 assert(is_palindrome(908) is False)
 
-
-

Get potential solutions. Generating a list comprehension which sorts the products in decreasing order is actually not that easys. This is because if we use two ranges it is not straight foward to decide which product is smaller or bigger. In the following example. 9 times 7 is still bigger than 8 times 8, but 9 times 6 is not anymore. So let's go for brute force the hard way.

-
-
In [2]:
+
In [2]:
-
+
pairs = ((a, b) for a in range(9, 0, -1) for b in range(a, 0, -1))
 print(list(pairs))
 
-
-
- -
-
- -
[(9, 9), (9, 8), (9, 7), (9, 6), (9, 5), (9, 4), (9, 3), (9, 2), (9, 1), (8, 8), (8, 7), (8, 6), (8, 5), (8, 4), (8, 3), (8, 2), (8, 1), (7, 7), (7, 6), (7, 5), (7, 4), (7, 3), (7, 2), (7, 1), (6, 6), (6, 5), (6, 4), (6, 3), (6, 2), (6, 1), (5, 5), (5, 4), (5, 3), (5, 2), (5, 1), (4, 4), (4, 3), (4, 2), (4, 1), (3, 3), (3, 2), (3, 1), (2, 2), (2, 1), (1, 1)]
 
-
-

We iterate over all 3-digit pairs. Two avoid duplicates the second range starts at the current value of the first range. If the new product is greater than the old one and a palindrome we have found a new result.

-
-
In [4]:
+
In [4]:
-
+
import timeit
 
 def brute_force():
@@ -11886,45 +11866,35 @@ div#notebook {
 print(timeit.timeit(brute_force, number=100))
 print(brute_force())
 
-
-
- -
-
- -
2.844880788875627
 906609
 
-
-

To do some more optimization we can simply break the loops if the square of the outer loop is smaller than the current result. If we find the solution quiet early this will prevent iterating through a lot of values which cannot yield a better result.

-
-
In [5]:
+
In [5]:
-
+
def brute_force():
     r = 0
     for a in range(999, 99, -1):
@@ -11939,36 +11909,23 @@ div#notebook {
 print(timeit.timeit(brute_force, number=100))
 print(brute_force())
 
-
-
- -
-
- -
0.562125718678324
 906609
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem005.html b/ipython/html/EulerProblem005.html index 6722199..5ac966d 100644 --- a/ipython/html/EulerProblem005.html +++ b/ipython/html/EulerProblem005.html @@ -1,9 +1,9 @@ + - + EulerProblem005 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem

2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.

+

Euler Problem

Back to overview.

2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.

What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?

-
@@ -11786,15 +11780,14 @@ div#notebook {

My easiest guess is to multiply all prime numbers till the number.

-
-
In [1]:
+
In [1]:
-
+
def get_primes_smaller(number):
     primes = []
     prospects = [n for n in range(2, number)]
@@ -11804,17 +11797,15 @@ div#notebook {
         primes.append(p)
     return primes
 
-
-
-
In [2]:
+
In [2]:
-
+
from operator import mul
 from functools import reduce
 
@@ -11824,44 +11815,34 @@ div#notebook {
 
 print(get_number_which_is_divisible_by_all_numbers_from_one_to(10))
 
-
-
- -
-
- -
210
 
-
-

That obviously didn't work. The reason is that the same prime can occur multiple times in the factorization of a divisor. For example $2^{3} = 8$. We can always brute force of course. We do a smart brute force and only check multiples from the product of primes because this factor must be part of the solution.

-
-
In [3]:
+
In [3]:
-
+
def is_divisible_by_numbers_smaller_or_equal(number, maximum_number):
     for n in range(2, maximum_number + 1):
         if number % n != 0:
@@ -11880,35 +11861,22 @@ div#notebook {
 assert(get_number_which_is_divisible_by_all_numbers_from_one_to(10) == 2520)
 print(get_number_which_is_divisible_by_all_numbers_from_one_to(20))
 
-
-
- -
-
- -
232792560
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem006.html b/ipython/html/EulerProblem006.html index 130e32b..3f4cfa1 100644 --- a/ipython/html/EulerProblem006.html +++ b/ipython/html/EulerProblem006.html @@ -1,9 +1,9 @@ + - + EulerProblem006 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 6

The sum of the squares of the first ten natural numbers is,

+

Euler Problem 6

Back to overview.

The sum of the squares of the first ten natural numbers is,

$1^2 + 2^2 + ... + 10^2 = 385$

The square of the sum of the first ten natural numbers is,

$(1 + 2 + ... + 10)^2 = 55^2 = 3025$

Hence the difference between the sum of the squares of the first ten natural numbers and the square of the sum is $3025 − 385 = 2640$.

Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.

-
@@ -11790,74 +11784,57 @@ div#notebook {

Okay, this is as straightforward as it can get.

-
-
In [1]:
+
In [1]:
-
+
s = sum([x for x in range(1, 101)])**2  - sum([x**2 for x in range(1, 101)])
 assert(s == 25164150)
 print(s)
 
-
-
- -
-
- -
25164150
 
-
-

General solution.

-
-
In [2]:
+
In [2]:
-
+
def diff_between_sum_of_squares_and_square_sum(n):
     return sum([x for x in range(1, n + 1)])**2  - sum([x**2 for x in range(1, n + 1)])
 
 assert(diff_between_sum_of_squares_and_square_sum(100) == 25164150)
 assert(diff_between_sum_of_squares_and_square_sum(10) == 2640)
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem007.html b/ipython/html/EulerProblem007.html index d6065d3..534a984 100644 --- a/ipython/html/EulerProblem007.html +++ b/ipython/html/EulerProblem007.html @@ -1,9 +1,9 @@ + - + EulerProblem007 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 7

By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.

+

Euler Problem 7

Back to overview.

By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.

What is the 10 001st prime number?

-
@@ -11786,15 +11780,14 @@ div#notebook {

We reuse our prime functions and use a trick from stackoverflow to get the nth element.

-
-
In [7]:
+
In [7]:
-
+
import itertools
 
 def is_prime(n, smaller_primes):
@@ -11822,35 +11815,22 @@ div#notebook {
 assert(get_nth_prime(6) == 13)
 print(get_nth_prime(10001))
 
-
-
- -
-
- -
104743
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem008.html b/ipython/html/EulerProblem008.html index cb634ca..bcfd7a1 100644 --- a/ipython/html/EulerProblem008.html +++ b/ipython/html/EulerProblem008.html @@ -1,9 +1,9 @@ + - + EulerProblem008 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 8

The four adjacent digits in the 1000-digit number that have the greatest product are 9 × 9 × 8 × 9 = 5832.

- +

Euler Problem 8

Back to overview.

The four adjacent digits in the 1000-digit number that have the greatest product are 9 × 9 × 8 × 9 = 5832.

73167176531330624919225119674426574742355349194934
 96983520312774506326239578318016984801869478851843
 85861560789112949495459501737958331952853208805511
@@ -11798,7 +11792,6 @@ div#notebook {
 05886116467109405077541002256983155200055935729725
 71636269561882670428252483600823257530420752963450

Find the thirteen adjacent digits in the 1000-digit number that have the greatest product. What is the value of this product?

-
@@ -11807,20 +11800,19 @@ div#notebook {

We need the number as a list of integers first.

-
-
In [1]:
+
In [1]:
-
+
def remove_newlines(s):
     import re
-    return re.sub(r'\n', '', s)
+    return re.sub(r'\n', '', s)
 
-digits_string = """73167176531330624919225119674426574742355349194934
+digits_string = """73167176531330624919225119674426574742355349194934
 96983520312774506326239578318016984801869478851843
 85861560789112949495459501737958331952853208805511
 12540698747158523863050715693290963295227443043557
@@ -11839,30 +11831,27 @@ div#notebook {
 07198403850962455444362981230987879927244284909188
 84580156166097919133875499200524063689912560717606
 05886116467109405077541002256983155200055935729725
-71636269561882670428252483600823257530420752963450"""
+71636269561882670428252483600823257530420752963450"""
 
 digits = [int(d) for d in remove_newlines(digits_string)]
 
-
-

Then we can use slicing to do a brute force.

-
-
In [2]:
+
In [2]:
-
+
def product(xs):
     from operator import mul
     from functools import reduce
@@ -11875,35 +11864,22 @@ div#notebook {
 assert(get_largest_product_of_n_digits(digits, 13) == 23514624000)
 print(get_largest_product_of_n_digits(digits, 13))
 
-
-
- -
-
- -
23514624000
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem009.html b/ipython/html/EulerProblem009.html index be1c1ce..c6ca384 100644 --- a/ipython/html/EulerProblem009.html +++ b/ipython/html/EulerProblem009.html @@ -1,9 +1,9 @@ + - + EulerProblem009 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 9

A Pythagorean triplet is a set of three natural numbers, $a < b < c$, for which,

+

Euler Problem 9

Back to overview.

A Pythagorean triplet is a set of three natural numbers, $a < b < c$, for which,

$a^2 + b^2 = c^2$

For example, $3^2 + 4^2 = 9 + 16 = 25 = 5^2$.

There exists exactly one Pythagorean triplet for which $a + b + c = 1000$. Find the product $abc$.

-
@@ -11789,15 +11783,14 @@ Find the product $abc$.

We start bruteforcing even though it feels like there may be a smart solution.

-
-
In [1]:
+
In [1]:
-
+
import timeit
 
 def brute_force():
@@ -11810,45 +11803,35 @@ Find the product $abc$.

print(timeit.timeit(brute_force, number=10)) print(brute_force())
-
-
- -
-
- -
66.96907186399949
 31875000
 
-
-

Let's do some optimization by cancelling the loops when we exceed the boundaries. Actually, I have also realized that choosing 251 and 501 is a little bit arbitrary. For example if a, b, c where something like $332, 333, 335$ that could be a solution and the first range was too low. Then again, we would have realized that as soon as we get back None, so it is okay.

-
-
In [2]:
+
In [2]:
-
+
def brute_force():
     for a in range(1, 251):
         for b in range(a + 1, 501):
@@ -11861,45 +11844,35 @@ Find the product $abc$.

print(timeit.timeit(brute_force, number=10)) print(brute_force())
-
-
- -
-
- -
64.4656584559998
 31875000
 
-
-

Big time save. Kappa. Okay, I am stupid. If I have a and b I can calculate c and check if it is a solution.

-
-
In [3]:
+
In [3]:
-
+
def smart_brute_force():
     for a in range(1, 251):
         for b in range(a + 1, 501):
@@ -11910,49 +11883,34 @@ Find the product $abc$.

print(timeit.timeit(smart_brute_force, number=10)) print(smart_brute_force())
-
-
- -
-
- -
0.22822808900036762
 31875000
 
-
-
-
In [ ]:
+
In [ ]:
-
+
 
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem010.html b/ipython/html/EulerProblem010.html index acc33ef..0bc25dc 100644 --- a/ipython/html/EulerProblem010.html +++ b/ipython/html/EulerProblem010.html @@ -1,9 +1,9 @@ + - + EulerProblem010 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 10

The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.

+

Euler Problem 10

Back to overview.

The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.

Find the sum of all the primes below two million.

-
@@ -11786,15 +11780,14 @@ div#notebook {

Okay, reuse prime generator from 7 and go.

-
-
In [1]:
+
In [1]:
-
+
import timeit
 
 def is_prime(n, smaller_primes):
@@ -11828,45 +11821,35 @@ div#notebook {
 assert(brute_force() == 142913828922)
 print(brute_force())
 
-
-
- -
-
- -
61.8695481220002
 142913828922
 
-
-

Okay, here it may actually be way smarter to use a sieve. We implent it because the old one was shitty. Okay, I am actually interested in the time difference. So we use the old one first and then implement the optimization.

-
-
In [2]:
+
In [2]:
-
+
def get_primes_smaller(number):
     primes = []
     prospects = [n for n in range(2, number)]
@@ -11882,26 +11865,23 @@ div#notebook {
 #print(timeit.timeit(brute_force, number=1))
 #print(brute_force())
 
-
-

This did not even terminate. We optimize the sieve by stopping when $p^2 > number$.

-
-
In [3]:
+
In [3]:
-
+
def sieve_of_eratosthenes(number):
     primes = []
     prospects = [n for n in range(2, number)]
@@ -11921,45 +11901,31 @@ div#notebook {
 assert(brute_force() == 142913828922)
 print(brute_force())
 
-
-
- -
-
- -
74.5315607270004
 142913828922
 
-
-

Okay, I honestly did not expect this to be slower than our generator. Gotta keep that in mind for future prime related problems.

-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem011.html b/ipython/html/EulerProblem011.html index 5b77f24..dd0d10f 100644 --- a/ipython/html/EulerProblem011.html +++ b/ipython/html/EulerProblem011.html @@ -1,9 +1,9 @@ + - + EulerProblem011 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 11

In the 20×20 grid below, four numbers along a diagonal line have been marked in red.

- +

Euler Problem 11

Back to overview.

In the 20×20 grid below, four numbers along a diagonal line have been marked in red.

08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
 49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
 81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
@@ -11799,7 +11793,6 @@ div#notebook {
 01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48

The product of these numbers is $26 × 63 × 78 × 14 = 1788696$.

What is the greatest product of four adjacent numbers in the same direction (up, down, left, right, or diagonally) in the 20×20 grid?

-
@@ -11809,16 +11802,15 @@ div#notebook {

We start by parsing the array into three lists of lists (horizontal, diagonal, vertical).

97, 17, 79, 11, 89, 44, 38, 94, 78, 0, 62, 54, 58, 4, 27, 53, 36, 1, 1, 1]

-
-
In [1]:
+
In [1]:
-
-
s = """
+
+
s = """
 08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
 49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
 81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
@@ -11839,7 +11831,7 @@ div#notebook {
 20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
 20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
 01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48
-"""
+"""
 
 def get_index(xs, index, default):
     if index < 0:
@@ -11849,16 +11841,14 @@ div#notebook {
     except IndexError:
         return default
 
-hss = [list(map(int, h.split())) for h in s.split('\n') if h]
+hss = [list(map(int, h.split())) for h in s.split('\n') if h]
 vss = [list(vs) for vs in zip(*hss)]
 # diagonal from top left to bottom right
 dss = [[get_index(hs, -19 + i + j, 1) for j, hs in enumerate(hss)] for i in range(39)]
 
-
-
@@ -11866,15 +11856,14 @@ div#notebook {

I really love the way we retrieve the vertical list. (We need the ugly conversion to list because otherwise we cannot concatenate them.) It is at the limit of my mental capabilities to understand why this works. But actually it is quite straight forward. If we provide two lists, zip creates a two-tuple for each field in the lists. If we provide n lists, zip creates a n-tuple for each field in the lists. Easy.

Now we create big list of lists and search each one for the greates four product and then get the maximum. Straight forward. We borrow the find product function from problem 8 because I like it.

-
-
In [2]:
+
In [2]:
-
+
xss = hss + vss + dss
 
 def product(xs):
@@ -11888,26 +11877,23 @@ div#notebook {
 s = max([get_largest_product_of_n_digits(xs, 4) for xs in xss])
 assert(s != 70600674)
 
-
-

Okay, I am actually really dumb. I forgot about the other diagonal. I think I have made the same mistake back when I solved this for the first time. So let's get the missing dss and get the solution.

-
-
In [3]:
+
In [3]:
-
+
# diagonal from bottom left to top right
 hss.reverse()
 dss = [[get_index(hs, -19 + i + j, 1) for j, hs in enumerate(hss)] for i in range(39)]
@@ -11916,35 +11902,22 @@ div#notebook {
 assert(s == 70600674)
 print(s)
 
-
-
- -
-
- -
70600674
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem012.html b/ipython/html/EulerProblem012.html index 53d7fe7..8e70cae 100644 --- a/ipython/html/EulerProblem012.html +++ b/ipython/html/EulerProblem012.html @@ -1,9 +1,9 @@ + - + EulerProblem012 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 12

The sequence of triangle numbers is generated by adding the natural numbers. So the 7th triangle number would be $1 + 2 + 3 + 4 + 5 + 6 + 7 = 28$. The first ten terms would be:

+

Euler Problem 12

Back to overview.

The sequence of triangle numbers is generated by adding the natural numbers. So the 7th triangle number would be $1 + 2 + 3 + 4 + 5 + 6 + 7 = 28$. The first ten terms would be:

$1, 3, 6, 10, 15, 21, 28, 36, 45, 55, \dots$

Let us list the factors of the first seven triangle numbers:

-
 1: 1
  3: 1,3
  6: 1,2,3,6
@@ -11788,7 +11782,6 @@ div#notebook {
 28: 1,2,4,7,14,28

We can see that 28 is the first triangle number to have over five divisors.

What is the value of the first triangle number to have over five hundred divisors?

-
@@ -11797,15 +11790,14 @@ div#notebook {

Let's try brute forcing.

-
-
In [5]:
+
In [5]:
-
+
def get_divisors(n):
     return [i for i in range(1, int(n/2) + 1) if n % i == 0] + [n]
 
@@ -11823,21 +11815,17 @@ div#notebook {
 #        print(t)
 #        break
 
-
-

That failed miserably. We have to come up with something more efficient. I looked at my old Haskell solution which looks like this:

-
divisor_count' x = product . map (succ . length) . group $ prim_factors x

Add first I did not understand what it does at all. But the algorithm is as follows:

-
# get prime factors, for example for 28
 2 * 2 * 7
 # group the primes
@@ -11847,15 +11835,14 @@ div#notebook {
 # get the product of all values
 6

Honestly, I have no idea why this gives as the number of divisors. I will implement the solution and then try to come up with an explanation.

-
-
In [6]:
+
In [6]:
-
+
def is_prime(n, smaller_primes):
     for s in smaller_primes:
         if n % s == 0:
@@ -11888,26 +11875,23 @@ div#notebook {
         factors.append(remainder)
     return factors
 
-
-

This are the prime numbers related functions we already now. Now we implement a group function, the product function we already know, and based on that the algorithm to get the number of divisors mentioned above.

-
-
In [7]:
+
In [7]:
-
+
def group(xs):
     from functools import reduce
     def f(xss, x):
@@ -11937,83 +11921,64 @@ div#notebook {
             
 assert(get_number_of_divisors(28) == 6)
 
-
-

Now we are ready to do another brute force attempt.

-
-
In [8]:
+
In [8]:
-
+
ts = triangle_number_generator_function()
 for t in ts:
     if get_number_of_divisors(t) > 500:
         print(t)
         break
 
-
-
- -
-
- -
76576500
 
-
-

Now the only question is why this crazy algorithm works. Okay, I got it with the help of this page. The problem is actually an instance of the multiplication principle for counting things. Each prime can be used to calculate (n + 1) other divisors. The incrementation by one is required because we can also choose to not use a certain prime. Of course, to get the potential combinations we have to get the product of the potential divisors for all primes. The web page explains it better. The only question is whether I came up with this algorithm myself back then.

-
-
In [ ]:
+
In [ ]:
-
+
 
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem013.html b/ipython/html/EulerProblem013.html index 05794bf..10928db 100644 --- a/ipython/html/EulerProblem013.html +++ b/ipython/html/EulerProblem013.html @@ -1,9 +1,9 @@ + - + EulerProblem013 - - - - - - + - - - + + - + -
-
- +
+
-

Work out the first ten digits of the sum of the following one-hundred 50-digit numbers.

- +

Euler Problem 13

Back to overview.

Work out the first ten digits of the sum of the following one-hundred 50-digit numbers.

37107287533902102798797998220837590246510135740250
 46376937677490009712648124896970078050417018260538
 74324986199524741059474233309513058123726617309629
@@ -11877,7 +11871,6 @@ div#notebook {
 72107838435069186155435662884062257473692284509516
 20849603980134001723930671666823555245252804609722
 53503534226472524250874054075591789781264330331690
-
@@ -11886,16 +11879,15 @@ div#notebook {

Straight forward. No big deal.

-
-
In [10]:
+
In [10]:
-
-
numbers_string = """
+
+
numbers_string = """
 37107287533902102798797998220837590246510135740250
 46376937677490009712648124896970078050417018260538
 74324986199524741059474233309513058123726617309629
@@ -11996,43 +11988,30 @@ div#notebook {
 72107838435069186155435662884062257473692284509516
 20849603980134001723930671666823555245252804609722
 53503534226472524250874054075591789781264330331690
-"""
+"""
 
-numbers = [int(n) for n in numbers_string.split('\n') if n]
+numbers = [int(n) for n in numbers_string.split('\n') if n]
 numbers_sum = sum(numbers)
 first_ten_digits = str(numbers_sum)[:10]
-assert(first_ten_digits == "5537376230")
+assert(first_ten_digits == "5537376230")
 print(first_ten_digits)
 
-
-
- -
-
- -
5537376230
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem014.html b/ipython/html/EulerProblem014.html index 7f40345..12884bf 100644 --- a/ipython/html/EulerProblem014.html +++ b/ipython/html/EulerProblem014.html @@ -1,9 +1,9 @@ + - + EulerProblem014 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 14

The following iterative sequence is defined for the set of positive integers:

+

Euler Problem 14

Back to overview.

The following iterative sequence is defined for the set of positive integers:

n → n/2 (n is even) n → 3n + 1 (n is odd)

Using the rule above and starting with 13, we generate the following sequence:

@@ -11783,7 +11778,6 @@ n → 3n + 1 (n is odd)

It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. Although it has not been proved yet (Collatz Problem), it is thought that all starting numbers finish at 1.

Which starting number, under one million, produces the longest chain?

NOTE: Once the chain starts the terms are allowed to go above one million.

-
@@ -11792,15 +11786,14 @@ n → 3n + 1 (n is odd)

I would go for a recursive function with a cache here. This should give us good performance with acceptable memory footprint.

-
-
In [1]:
+
In [1]:
-
+
from functools import lru_cache
 from collections import deque
 
@@ -11814,62 +11807,50 @@ n → 3n + 1 (n is odd)

assert(list(get_collatz_sequence(13)) == [13, 40, 20, 10, 5, 16, 8, 4, 2, 1])
-
-

Isn't this a beautiful solution? We need a deque to appendleft. Of course, we could also use a regular list and reverse the result, but it is nicer to get the correct solution out right away. Now we simply force the solution.

-
-
In [2]:
+
In [2]:
-
+
try:
     s = max([(len(get_collatz_sequence(i)), i) for i in range(1000000)])
     print(s)
     assert(s == 837799)
 except RecursionError:
-    print("Okay, we need a loop.")
+    print("Okay, we need a loop.")
 
-
-
- -
-
- -
Okay, we need a loop.
 
-
-
-
In [3]:
+
In [3]:
-
+
cache = {}
 
 def get_collatz_sequence(n):
@@ -11900,45 +11881,31 @@ n → 3n + 1 (n is odd)

print(timeit.timeit(brute_force, number=10)) print(brute_force())
-
-
- -
-
- -
11.4885111964837
 837799
 
-
-

Here we go. Takes some time. We could optimize by caching only the length and not the complete list.

-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem015.html b/ipython/html/EulerProblem015.html index ce77fb0..24618db 100644 --- a/ipython/html/EulerProblem015.html +++ b/ipython/html/EulerProblem015.html @@ -1,9 +1,9 @@ + - + EulerProblem015 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 15

Starting in the top left corner of a 2×2 grid, and only being able to move to the right and down, there are exactly 6 routes to the bottom right corner.

-

problem picture

+

Euler Problem 15

Back to overview.

Starting in the top left corner of a 2×2 grid, and only being able to move to the right and down, there are exactly 6 routes to the bottom right corner.

+

problem picture

How many such routes are there through a 20×20 grid?

-
@@ -11788,21 +11782,19 @@ div#notebook {

We should be able to get this with some thinking. Every move for a $nxn$ grid has to contain n downward and n rightward moves. So in total there are 2n moves. Now we only have to get all permutations available with 2n moves. Normally, we would calculate the factorial, but this only works if all symbols are different. In this case we always only have two symbols for the 2n moves. For each solution there exist a certain number of ways we can create this solution. Let's assume we have two right arrows called (1, 2) and two down arrows called (3, 4). We now have the following options to generate the solution in the upper left corner.

-
1 2 3 4
 1 2 4 3
 2 1 3 4
 2 1 4 2

So this means if we calculate the number of ways using the factorial $(2\times2)! = 4! = 24$, four of the solutions are equal which gives us $\frac{24}{4} = 6$. The way to calculate the four should be $2! \times 2! = 4$, so our formula is $\frac{(2\times n)!}{n! \times n!}$. So let's try that.

-
-
In [4]:
+
In [4]:
-
+
def get_number_of_routes(n):
     from math import factorial
     return factorial(2 * n) // (factorial(n) * factorial(n))
@@ -11811,29 +11803,20 @@ For each solution there exist a certain number of ways we can create this soluti
 assert(get_number_of_routes(20) == 137846528820)
 print(get_number_of_routes(20))
 
-
-
- -
-
- -
137846528820
 
-
-
@@ -11843,15 +11826,10 @@ For each solution there exist a certain number of ways we can create this soluti

So the final formula is

$n_{routes} = \frac{(d \times n)!}{(n!)^d}$

where d is the number of dimensions and n is the size of the grid.

-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem016.html b/ipython/html/EulerProblem016.html index 96abdee..f4a50ed 100644 --- a/ipython/html/EulerProblem016.html +++ b/ipython/html/EulerProblem016.html @@ -1,9 +1,9 @@ + - + EulerProblem016 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 16

$2^{15}$ = 32768 and the sum of its digits is 3 + 2 + 7 + 6 + 8 = 26.

+

Euler Problem 16

Back to overview.

$2^{15}$ = 32768 and the sum of its digits is 3 + 2 + 7 + 6 + 8 = 26.

What is the sum of the digits of the number $2^{1000}$?

-
@@ -11786,57 +11780,46 @@ div#notebook {

Seriously? Okay, probably more difficult in C.

-
-
In [17]:
+
In [17]:
-
+
s = sum(map(int, str(2**1000)))
 assert(s == 1366)
 print(s)
 
-
-
- -
-
- -
1366
 
-
-

Okay, let's do it without big ints.

-
-
In [18]:
+
In [18]:
-
+
def double_number_string(number_string):
     number_string = number_string[::-1] # reverse
     result = []
@@ -11848,77 +11831,61 @@ div#notebook {
         result.append(str(next_digit))
     if carriage > 0:
         result.append(str(carriage))
-    result = "".join(result)[::-1]
+    result = "".join(result)[::-1]
     return result
 
-assert(double_number_string("132") == "264")
-assert(double_number_string("965") == "1930")
+assert(double_number_string("132") == "264")
+assert(double_number_string("965") == "1930")
 
-
-
-
In [19]:
+
In [19]:
-
+
def powers_of_two(n):
-    """ Retuns nth power of two as a string. """
+    """ Retuns nth power of two as a string. """
     assert(n >= 0)
     if n == 0:
-        return "1"
-    s = "2"
+        return "1"
+    s = "2"
     for _ in range(n - 1):
         s = double_number_string(s)
     return s
 
-assert(powers_of_two(3) == "8")
-assert(powers_of_two(10) == "1024")
+assert(powers_of_two(3) == "8")
+assert(powers_of_two(10) == "1024")
 
 number_string = powers_of_two(1000)
 print(sum(map(int, number_string)))
 
-
-
- -
-
- -
1366
 
-
-

Here we go. The conversion to integer and the sum would be easy in C.

-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem017.html b/ipython/html/EulerProblem017.html index 0a6606e..b7ab387 100644 --- a/ipython/html/EulerProblem017.html +++ b/ipython/html/EulerProblem017.html @@ -1,9 +1,9 @@ + - + EulerProblem017 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 17

If the numbers 1 to 5 are written out in words: one, two, three, four, five, then there are 3 + 3 + 5 + 4 + 4 = 19 letters used in total.

+

Euler Problem 17

Back to overview.

If the numbers 1 to 5 are written out in words: one, two, three, four, five, then there are 3 + 3 + 5 + 4 + 4 = 19 letters used in total.

If all the numbers from 1 to 1000 (one thousand) inclusive were written out in words, how many letters would be used?

NOTE: Do not count spaces or hyphens. For example, 342 (three hundred and forty-two) contains 23 letters and 115 (one hundred and fifteen) contains 20 letters. The use of "and" when writing out numbers is in compliance with British usage.

-
@@ -11787,50 +11781,49 @@ div#notebook {

I can see us doing a semi-automated approach here or we write a nice function. We probably write a nice function because we are geeks.

-
-
In [1]:
+
In [1]:
-
+
def single_digit_integer_to_spoken_language(n):
     if n == 0:
-        return ""
+        return ""
     assert(n > 0 and n < 10)
-    return {1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five',
-            6: 'six', 7: 'seven', 8: 'eight', 9: 'nine'}[n]
+    return {1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five',
+            6: 'six', 7: 'seven', 8: 'eight', 9: 'nine'}[n]
 
 def double_digit_integer_to_spoken_language(n):
     assert(n > 9 and n < 100)
     try:
         return {
-            10: 'ten', 11: 'eleven', 12: 'twelve', 13: 'thirteen', 
-            14: 'fourteen', 15: 'fifteen', 16: 'sixteen',
-            17: 'seventeen', 18: 'eighteen', 19: 'nineteen'}[n]
+            10: 'ten', 11: 'eleven', 12: 'twelve', 13: 'thirteen', 
+            14: 'fourteen', 15: 'fifteen', 16: 'sixteen',
+            17: 'seventeen', 18: 'eighteen', 19: 'nineteen'}[n]
     except KeyError:
         pass
     a, b = str(n)
-    a = {2: 'twenty', 3: 'thirty', 4: 'forty', 5: 'fifty',
-         6: 'sixty', 7: 'seventy', 8: 'eighty', 9: 'ninety'}[int(a)]
+    a = {2: 'twenty', 3: 'thirty', 4: 'forty', 5: 'fifty',
+         6: 'sixty', 7: 'seventy', 8: 'eighty', 9: 'ninety'}[int(a)]
     b = integer_to_spoken_language(int(b))
-    return a + '-' + b
+    return a + '-' + b
 
 def triple_digit_integer_to_spoken_language(n):
     a, b = str(n)[0], str(n)[1:]
     a = single_digit_integer_to_spoken_language(int(a))
     b = integer_to_spoken_language(int(b))
     if not b:
-        return a + " hundred"
-    return a + " hundred and " + b
+        return a + " hundred"
+    return a + " hundred and " + b
 
 def four_digit_integer_to_spoken_language(n):
     a, b = str(n)[0], str(n)[1:]
     a = single_digit_integer_to_spoken_language(int(a))
     b = integer_to_spoken_language(int(b))  
-    return a + " thousand " + b
+    return a + " thousand " + b
 
 def integer_to_spoken_language(n):
     l = len(str(n))
@@ -11843,77 +11836,60 @@ div#notebook {
     elif l == 4:
         return four_digit_integer_to_spoken_language(n)
     else:
-        raise Exception("Length not supported.")
+        raise Exception("Length not supported.")
 
-assert(integer_to_spoken_language(5) == 'five')
-assert(integer_to_spoken_language(19) == 'nineteen')
-assert(integer_to_spoken_language(21) == 'twenty-one')
-assert(integer_to_spoken_language(210) == 'two hundred and ten')
-assert(integer_to_spoken_language(3000) == 'three thousand ')
-assert(integer_to_spoken_language(8333) == 'eight thousand three hundred and thirty-three')
+assert(integer_to_spoken_language(5) == 'five')
+assert(integer_to_spoken_language(19) == 'nineteen')
+assert(integer_to_spoken_language(21) == 'twenty-one')
+assert(integer_to_spoken_language(210) == 'two hundred and ten')
+assert(integer_to_spoken_language(3000) == 'three thousand ')
+assert(integer_to_spoken_language(8333) == 'eight thousand three hundred and thirty-three')
 
-
-

Okay, I won't win a code golf contest but at least we can get the solution now.

-
-
In [2]:
+
In [2]:
-
-
l = len("".join([integer_to_spoken_language(i) for i in range(1, 1001)]).replace(" ", "").replace("-", ""))
+
+
l = len("".join([integer_to_spoken_language(i) for i in range(1, 1001)]).replace(" ", "").replace("-", ""))
 assert(l == 21124)
 print(l)
 
-
-
- -
-
- -
21124
 
-
-

Made the classical fourty/forty error I have already done four years ago. Some things don't change. Also I still do not really like this problem. The Haskell solution is actually way easier to read this time.

-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem018.html b/ipython/html/EulerProblem018.html index d6df356..6b52706 100644 --- a/ipython/html/EulerProblem018.html +++ b/ipython/html/EulerProblem018.html @@ -1,9 +1,9 @@ + - + EulerProblem018 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 18

By starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom is 23.

- +

Euler Problem 18

Back to overview.

By starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom is 23.

                    3
                    7 4
                   2 4 6
                  8 5 9 3

That is, 3 + 7 + 4 + 9 = 23.

Find the maximum total from top to bottom of the triangle below:

-
75
 95 64
 17 47 82
@@ -11800,7 +11793,6 @@ div#notebook {
 63 66 04 68 89 53 67 30 73 16 69 87 40 31
 04 62 98 27 23 09 70 98 73 93 38 53 60 04 23

NOTE: As there are only 16384 routes, it is possible to solve this problem by trying every route. However, Problem 67, is the same challenge with a triangle containing one-hundred rows; it cannot be solved by brute force, and requires a clever method! ;o)

-
@@ -11810,22 +11802,19 @@ div#notebook {

This is incredibly simple we simply from bottom to top choosing the higher value for each mini-tree.

For example,

-
  95  64
 17  47  82

will become:

-
 142 146
-
-
In [1]:
+
In [1]:
-
-
t = """
+
+
t = """
 75
 95 64
 17 47 82
@@ -11841,110 +11830,89 @@ div#notebook {
 91 71 52 38 17 14 91 43 58 50 27 29 48
 63 66 04 68 89 53 67 30 73 16 69 87 40 31
 04 62 98 27 23 09 70 98 73 93 38 53 60 04 23
-"""
+"""
 
-
-
-
In [2]:
+
In [2]:
-
+
def reduce_rows(xs, ys):
-    """ xs is lower row and ys is upper row """
+    """ xs is lower row and ys is upper row """
     assert(len(xs) == len(ys) + 1)
     return [max([xs[i] + ys[i], xs[i + 1] + ys[i]]) for i in range(len(ys))]
         
 assert(reduce_rows([17, 47, 82], [95, 64]) == [142, 146])
 
-
-

Okay, now all we have to do is the parsing and then a simple fold.

-
-
In [3]:
+
In [3]:
-
-
xss = [list(map(int, xs.split())) for xs in t.split("\n") if xs]
+
+
xss = [list(map(int, xs.split())) for xs in t.split("\n") if xs]
 xss.reverse()
 from functools import reduce
 s = reduce(reduce_rows, xss[1:], xss[0])[0]
 assert(s == 1074)
 
-
-

Okay, let's put this into a nice function an then solve problem 67 right away.

-
-
In [4]:
+
In [4]:
-
+
def find_greatest_path_sum_in_triangle_string(ts):
     from functools import reduce
-    xss = [list(map(int, xs.split())) for xs in ts.split("\n") if xs]
+    xss = [list(map(int, xs.split())) for xs in ts.split("\n") if xs]
     xss.reverse()
     r = lambda xs, ys: [max([xs[i] + ys[i], xs[i + 1] + ys[i]]) for i in range(len(ys))]
     return reduce(r, xss[1:], xss[0])[0]
 
 print(find_greatest_path_sum_in_triangle_string(t))
 
-
-
- -
-
- -
1074
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem019.html b/ipython/html/EulerProblem019.html index e4ad6e6..3791071 100644 --- a/ipython/html/EulerProblem019.html +++ b/ipython/html/EulerProblem019.html @@ -1,9 +1,9 @@ + - + EulerProblem019 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 19

You are given the following information, but you may prefer to do some research for yourself.

+

Euler Problem 19

Back to overview.

You are given the following information, but you may prefer to do some research for yourself.

  • 1 Jan 1900 was a Monday.
  • Thirty days has September, @@ -11787,7 +11782,6 @@ And on leap years, twenty-nine.
  • A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400.

How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?

-
@@ -11799,24 +11793,23 @@ And on leap years, twenty-nine.

We have one hundred years which equal 1200 months. Every month starts with a weekday and $\frac{1}{7}$ of all weekdays are Sundays. So, 1200 divided by 7 is 171 point something.

Which turns out to be the correct solution.

Let's still code a solution because we were not that smart back then. We create two generators, zip, them and search for 1st and Sunday.

-
-
In [1]:
+
In [1]:
-
+
def weekday_generator_function():
     while True:
-        yield 'Monday'
-        yield 'Tuesday'
-        yield 'Wednesday'
-        yield 'Thursday'
-        yield 'Friday'
-        yield 'Saturday'
-        yield 'Sunday'
+        yield 'Monday'
+        yield 'Tuesday'
+        yield 'Wednesday'
+        yield 'Thursday'
+        yield 'Friday'
+        yield 'Saturday'
+        yield 'Sunday'
         
 def day_of_month_generator_function():
     day, month, year = 1, 1, 1901
@@ -11844,91 +11837,67 @@ And on leap years, twenty-nine.
 
         
 ds = zip(weekday_generator_function(), day_of_month_generator_function())
-s = len([1 for weekday, date in ds if weekday == "Sunday" and date == 1])
+s = len([1 for weekday, date in ds if weekday == "Sunday" and date == 1])
 print(s)
 
-
-
- -
-
- -
172
 
-
-

Okay, this is actually kind of embarrassing. Why am I even zipping when I have the month right there in my function. Problem is, that my weekday generator starts with Monday, but Monday was the start in 1900 not in 1901. Let's try to do better. 1.1.1901 was a Tuesday, so we drop Monday from the generator.

-
-
In [2]:
+
In [2]:
-
+
wds = weekday_generator_function()
 next(wds) # get rid of first Monday
 ds = zip(wds, day_of_month_generator_function())
-s = len([1 for weekday, date in ds if weekday == "Sunday" and date == 1])
+s = len([1 for weekday, date in ds if weekday == "Sunday" and date == 1])
 print(s)
 
-
-
- -
-
- -
171
 
-
-

And finally, here we go. Actually not a dummy exercise and shows how imporessive the shortcut from the beginning is. Raw power is not always the best solution if we can also use brain.

-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem020.html b/ipython/html/EulerProblem020.html index 9c2365a..c73c3e6 100644 --- a/ipython/html/EulerProblem020.html +++ b/ipython/html/EulerProblem020.html @@ -1,9 +1,9 @@ + - + EulerProblem020 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 20

n! means n × (n − 1) × ... × 3 × 2 × 1

+

Euler Problem 20

Back to overview.

n! means n × (n − 1) × ... × 3 × 2 × 1

For example, 10! = 10 × 9 × ... × 3 × 2 × 1 = 3628800, and the sum of the digits in the number 10! is 3 + 6 + 2 + 8 + 8 + 0 + 0 = 27.

Find the sum of the digits in the number 100!

-
@@ -11788,15 +11782,14 @@ and the sum of the digits in the number 10! is 3 + 6 + 2 + 8 + 8 + 0 + 0 = 27.

Write our own factorial implementation and get the solution.

-
-
In [1]:
+
In [1]:
-
+
def factorial(n):
     assert(n > 0)
     if n == 1:
@@ -11804,50 +11797,35 @@ and the sum of the digits in the number 10! is 3 + 6 + 2 + 8 + 8 + 0 + 0 = 27.else:
         return n * factorial(n - 1)
 
-
-
-
In [2]:
+
In [2]:
-
+
f100 = factorial(100)
 print(sum(map(int, str(f100))))
 assert(sum(map(int, str(f100))) == 648)
 
-
-
- -
-
- -
648
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem021.html b/ipython/html/EulerProblem021.html index 7b9d5d5..b19a77a 100644 --- a/ipython/html/EulerProblem021.html +++ b/ipython/html/EulerProblem021.html @@ -1,9 +1,9 @@ + - + EulerProblem021 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 21

Let d(n) be defined as the sum of proper divisors of n (numbers less than n which divide evenly into n). +

Euler Problem 21

Back to overview.

Let d(n) be defined as the sum of proper divisors of n (numbers less than n which divide evenly into n). If d(a) = b and d(b) = a, where a ≠ b, then a and b are an amicable pair and each of a and b are called amicable numbers.

For example, the proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 and 110; therefore d(220) = 284. The proper divisors of 284 are 1, 2, 4, 71 and 142; so d(284) = 220.

Evaluate the sum of all the amicable numbers under 10000.

-
@@ -11788,15 +11782,14 @@ If d(a) = b and d(b) = a, where a ≠ b, then a and b are an amicable pair and e

We reuse the sieve of eratosthenes (which we called get_primes_smaller previously). What annoys me about the implementation is that we do not stop scanning for prospects once the current prime squared is greater than the limit. Let's test if it returns the same result and compare the execution time.

-
-
In [1]:
+
In [1]:
-
+
def get_primes_smaller(limit):
     primes = []
     prospects = [n for n in range(2, limit)]
@@ -11824,45 +11817,35 @@ If d(a) = b and d(b) = a, where a ≠ b, then a and b are an amicable pair and e
 print(timeit.timeit(functools.partial(sieve_of_eratosthenes, 10000), number=100))
 assert(get_primes_smaller(10000) == sieve_of_eratosthenes(10000))
 
-
-
- -
-
- -
5.062845234464119
 0.3188800166435408
 
-
-

Okay, this difference is sick actually. Interesting to see what the difference between O(sqrt(n)) and O(n) can mean. Now we can use the primes to do the factorization. I will again apply some optimizations and see how it turns out

-
-
In [2]:
+
In [2]:
-
+
def get_prime_factors_old(number):
     prime_generator = sieve_of_eratosthenes(number // 2)
     remainder = number
@@ -11897,30 +11880,21 @@ If d(a) = b and d(b) = a, where a ≠ b, then a and b are an amicable pair and e
 print(timeit.timeit(functools.partial(get_prime_factors, 1000000), number=10))
 assert(get_prime_factors_old(100000) == get_prime_factors(100000))
 
-
-
- -
-
- -
6.370271180404346
 5.785088868397899
 
-
-
@@ -11929,15 +11903,14 @@ If d(a) = b and d(b) = a, where a ≠ b, then a and b are an amicable pair and e

Okay, actually no big difference. Kind of expected if you check how similar the implementations are. I though stopping if p is greater than the remainder may be a common case.

Now we can use the prime factors to get all factors. For this each prime number can be used 0 to n times where n is the number how often the prime occurs in the prime factorization. For example, all possible fators for the primes $2, 2, 3$ are $2^0 \times 3^0, 2^1 \times 3^0, 2^2 \times 3^0, 2^0 \times 3^1, 2^1 \times 3^1, 2^2 \times 3^1$ which results in $1, 2, 4, 3, 6, 12$.

So we proceed in the following way. Once we have the prime factors we group then. Then we calculate the factors for each group. For example for $2,2$ the factors would be $1, 2, 4$ as explained in the previous paragraph. Then we calculate the combinations of all factor groups.

-
-
In [3]:
+
In [3]:
-
+
def group(xs):
     from functools import reduce
     rs = []
@@ -11962,11 +11935,9 @@ If d(a) = b and d(b) = a, where a ≠ b, then a and b are an amicable pair and e
 
 assert(group([1, 2, 2, 2, 4, 4, 5]) == [[1], [2, 2, 2], [4, 4], [5]])
 
-
-
@@ -11974,15 +11945,14 @@ If d(a) = b and d(b) = a, where a ≠ b, then a and b are an amicable pair and e

As you can see I had a fancy version with reduce first, but the loop is way more readable. We iterate over the input list. If the current item is in the last sublist of the return list we add it to the list. Otherwise we append a new sublist with the item.

Next we write a function that calculates the resulting factors for a factor group.

-
-
In [4]:
+
In [4]:
-
+
def prime_group_to_factors(group):
     f = group[0]
     n = len(group)
@@ -11990,68 +11960,60 @@ If d(a) = b and d(b) = a, where a ≠ b, then a and b are an amicable pair and e
 
 assert(prime_group_to_factors([2, 2, 2]) == [1, 2, 4, 8])
 
-
-

No we only have to get all factors by calculating the combination of two factor lists.

-
-
In [5]:
+
In [5]:
-
+
def combine_factors(xs, ys):
     return [x * y for y in ys for x in xs]
 
 assert(combine_factors([1, 2, 4], [1, 3]) == [1, 2, 4, 3, 6, 12])
 
-
-

Now actually we want to combine an arbitrary number of factor lists.

-
-
In [6]:
+
In [6]:
-
+
def combine_factors(xss):
     ys = [1]
     for xs in xss:
         ys = [x * y for y in ys for x in xs]
     return ys
 
-
-
-
In [7]:
+
In [7]:
-
+
def get_divisors(n):
     prime_factors = get_prime_factors(n)
     prime_groups = group(prime_factors)
@@ -12064,26 +12026,23 @@ If d(a) = b and d(b) = a, where a ≠ b, then a and b are an amicable pair and e
 assert(get_divisors(13) == [1, 13])
 assert(get_divisors(26) == [1, 2, 13, 26])
 
-
-

We can finally start to get the solution. Remember that we only want to get the sum of proper divisors which are the divisors withouth the number itself.

-
-
In [8]:
+
In [8]:
-
+
def sum_of_proper_divisors(number):
     return sum(get_divisors(number)[:-1])
 
@@ -12098,103 +12057,81 @@ If d(a) = b and d(b) = a, where a ≠ b, then a and b are an amicable pair and e
 
 assert(is_amicable(220))
 
-
-

The if statement is very import because a number pair $a, b$ is only amicable if $a \neq b$.

-
-
In [9]:
+
In [9]:
-
+
amicable_till_10000 = [i for i in range(1, 10000) if is_amicable(i)]
 assert(sum(amicable_till_10000) == 31626)
 print(sum(amicable_till_10000))
 
-
-
- -
-
- -
31626
 
-
-

I found some brute force solutions in the Euler forum and they claim to have a sick performance. I want to compare them.

-
-
In [10]:
+
In [10]:
-
+
def brute_force():
     return sum([i for i in range(1, 10000) if is_amicable(i)])
 
 import timeit
 print(timeit.timeit(brute_force, number=10))
 
-
-
- -
-
- -
108.68903765424807
 
-
-
-
In [14]:
+
In [14]:
-
+
def sum_of_proper_divisors(n):
     from math import sqrt
     s = 1
@@ -12218,29 +12155,20 @@ If d(a) = b and d(b) = a, where a ≠ b, then a and b are an amicable pair and e
 import timeit
 print(timeit.timeit(brute_force, number=10))
 
-
-
- -
-
- -
0.7862764837699387
 
-
-
@@ -12248,15 +12176,10 @@ If d(a) = b and d(b) = a, where a ≠ b, then a and b are an amicable pair and e

This is actually really embarrassing. Especially I was aware of the sqrt trick all the way but did not manage to put it into use properly. Another example where greate engineer will leave you far behind compared to great thinking.

Supplement: Also I have discovered that my sum of proper divisors function has a bug when n is a square, because in that case i == (n // 1) which adds this value two times. So there is no amicable number under 10000 which is also a square because otherwise we would have failed.

-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem022.html b/ipython/html/EulerProblem022.html index fe9d4fd..8542b59 100644 --- a/ipython/html/EulerProblem022.html +++ b/ipython/html/EulerProblem022.html @@ -1,9 +1,9 @@ + - + EulerProblem022 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 22

Using names.txt (saved as EulerProblem022.txt in the same directory as this notebook), a 46K text file containing over five-thousand first names, begin by sorting it into alphabetical order. Then working out the alphabetical value for each name, multiply this value by its alphabetical position in the list to obtain a name score.

+

Euler Problem 22

Back to overview.

Using names.txt (saved as EulerProblem022.txt in the same directory as this notebook), a 46K text file containing over five-thousand first names, begin by sorting it into alphabetical order. Then working out the alphabetical value for each name, multiply this value by its alphabetical position in the list to obtain a name score.

For example, when the list is sorted into alphabetical order, COLIN, which is worth 3 + 15 + 12 + 9 + 14 = 53, is the 938th name in the list. So, COLIN would obtain a score of 938 × 53 = 49714.

What is the total of all the name scores in the file?

-
@@ -11787,82 +11781,71 @@ div#notebook {

Okay, this should be straight forward.

-
-
In [ ]:
+
In [ ]:
-
-
with open('EulerProblem022.txt', 'r') as f:
-    names = f.read().split(',')
+
+
with open('EulerProblem022.txt', 'r') as f:
+    names = f.read().split(',')
 
 def get_score_for_name(name):
-    return sum([ord(c) - ord('A') + 1 for c in name if not c == '"'])
+    return sum([ord(c) - ord('A') + 1 for c in name if not c == '"'])
 
-assert(get_score_for_name('COLIN') == 53)
+assert(get_score_for_name('COLIN') == 53)
 names.sort()
 s = sum([(i + 1) * get_score_for_name(name) for i, name in enumerate(names)])
 assert(s == 871198282)
 print(s)
 
-
-

I think nothing to explain here. The only question is what was if we hadn't the Python sort function to sort into alphabetical order, then we would have to write our own compare function and use it with what ever sorting algorithm.

-
-
In [19]:
+
In [19]:
-
+
def compare(a, b):
     try:
         for i in range(len(a)):
             if a[i] < b[i]:
-                return '{} before {}'.format(a, b)
+                return '{} before {}'.format(a, b)
             elif a[i] > b[i]:
-                return '{} before {}'.format(b, a)
+                return '{} before {}'.format(b, a)
     except IndexError:
         pass
     if len(a) < len(b):
-        return '{} before {}'.format(a, b)
+        return '{} before {}'.format(a, b)
     elif len(a) > len(b):
-        return '{} before {}'.format(b, a)
+        return '{} before {}'.format(b, a)
     else:
-        return '{} is {}'.format(b, a)
+        return '{} is {}'.format(b, a)
 
-print(compare('Felix', 'Arnold'))
-print(compare('Felix', 'Felixb'))
-print(compare('Felixb', 'Felix'))
-print(compare('Felix', 'Felix'))
+print(compare('Felix', 'Arnold'))
+print(compare('Felix', 'Felixb'))
+print(compare('Felixb', 'Felix'))
+print(compare('Felix', 'Felix'))
 
-
-
- -
-
- -
Arnold before Felix
 Felix before Felixb
@@ -11871,25 +11854,18 @@ Felix is Felix
 
-
-

Obviously, the algorithm would return True/False or 0/1/-1 for real sorting.

-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem023.html b/ipython/html/EulerProblem023.html index fb7084e..de11dda 100644 --- a/ipython/html/EulerProblem023.html +++ b/ipython/html/EulerProblem023.html @@ -1,9 +1,9 @@ + - + EulerProblem023 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 23

A perfect number is a number for which the sum of its proper divisors is exactly equal to the number. For example, the sum of the proper divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.

+

Euler Problem 23

Back to overview.

A perfect number is a number for which the sum of its proper divisors is exactly equal to the number. For example, the sum of the proper divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.

A number n is called deficient if the sum of its proper divisors is less than n and it is called abundant if this sum exceeds n.

As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the smallest number that can be written as the sum of two abundant numbers is 24. By mathematical analysis, it can be shown that all integers greater than 28123 can be written as the sum of two abundant numbers. However, this upper limit cannot be reduced any further by analysis even though it is known that the greatest number that cannot be expressed as the sum of two abundant numbers is less than this limit.

Find the sum of all the positive integers which cannot be written as the sum of two abundant numbers.

-
@@ -11788,15 +11782,14 @@ div#notebook {

We reuse the sum of proper divisors function and use it to tell whether a number is abundant or not.

-
-
In [20]:
+
In [20]:
-
+
def sum_of_proper_divisors(n):
     from math import sqrt
     if n == 1:
@@ -11819,26 +11812,23 @@ div#notebook {
 abundant_numbers_smaller_30000 = [n for n in range(1, 30001) if is_abundant(n)]
 abundant_numbers_smaller_30000_set = set(abundant_numbers_smaller_30000)
 
-
-

Now that we have all abundant numbers in sorted order we can write a function which tests whether a number can be written as a sum of two abundant numbers.

-
-
In [21]:
+
In [21]:
-
+
def is_sum_of_two_abundants(n):
     for a in abundant_numbers_smaller_30000:
         if a > (n // 2):
@@ -11852,59 +11842,43 @@ div#notebook {
 assert(is_sum_of_two_abundants(23) == False)
 assert(is_sum_of_two_abundants(28123) == True)
 
-
-

Now we try to brute force.

-
-
In [34]:
+
In [34]:
-
+
s = sum([i for i in range(1, 30000) if not is_sum_of_two_abundants(i)])
 print(s)
 assert(s == 4179871)
 
-
-
- -
-
- -
4179871
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem024.html b/ipython/html/EulerProblem024.html index 16f1fde..938735f 100644 --- a/ipython/html/EulerProblem024.html +++ b/ipython/html/EulerProblem024.html @@ -1,9 +1,9 @@ + - + EulerProblem024 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 24

A permutation is an ordered arrangement of objects. For example, 3124 is one possible permutation of the digits 1, 2, 3 and 4. If all of the permutations are listed numerically or alphabetically, we call it lexicographic order. The lexicographic permutations of 0, 1 and 2 are:

+

Euler Problem 24

Back to overview.

A permutation is an ordered arrangement of objects. For example, 3124 is one possible permutation of the digits 1, 2, 3 and 4. If all of the permutations are listed numerically or alphabetically, we call it lexicographic order. The lexicographic permutations of 0, 1 and 2 are:

012 021 102 120 201 210

What is the millionth lexicographic permutation of the digits 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9?

-
@@ -11787,15 +11781,14 @@ div#notebook {

I tried to solve this by thinking and failed to be hones. So we implement a generator and get the millionth element.

-
-
In [19]:
+
In [19]:
-
+
from collections import deque
 
 def permutation_generator(xs):
@@ -11810,66 +11803,50 @@ div#notebook {
             yield y
     raise StopIteration
 
-assert(list(map(lambda s: "".join(s), permutation_generator("012"))) == ['012', '021', '102', '120', '201', '210'])
+assert(list(map(lambda s: "".join(s), permutation_generator("012"))) == ['012', '021', '102', '120', '201', '210'])
 
-
-

All right, now we reuse the function to get the nth element from problem 7 and give ourselves a solution.

-
-
In [26]:
+
In [26]:
-
+
def get_nth(generator, n):
     import itertools
     return next(itertools.islice(generator, n - 1, n))
 
-ps = permutation_generator("0123456789")
-s = int("".join(get_nth(ps, 1000000)))
+ps = permutation_generator("0123456789")
+s = int("".join(get_nth(ps, 1000000)))
 assert(s == 2783915460)
 print(s)
 
-
-
- -
-
- -
2783915460
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem025.html b/ipython/html/EulerProblem025.html index 69a110e..97ddc86 100644 --- a/ipython/html/EulerProblem025.html +++ b/ipython/html/EulerProblem025.html @@ -1,9 +1,9 @@ + - + EulerProblem025 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 25

The Fibonacci sequence is defined by the recurrence relation:

+

Euler Problem 25

Back to overview.

The Fibonacci sequence is defined by the recurrence relation:

$F_n = F_{n−1} + F_{n−2}$, where $F_1 = 1$ and $F_2 = 1$. Hence the first 12 terms will be:

-
F1 = 1
 F2 = 1
 F3 = 2
@@ -11793,7 +11787,6 @@ F11 = 89
 F12 = 144

The 12th term, $F_{12}$, is the first term to contain three digits.

What is the index of the first term in the Fibonacci sequence to contain 1000 digits?

-
@@ -11802,15 +11795,14 @@ F12 = 144

Reuse fibonacci generator and then straight forward.

-
-
In [4]:
+
In [4]:
-
+
def fibonacci_generator():
     a = 0
     b = 1
@@ -11827,35 +11819,22 @@ F12 = 144
assert(s == 4782) print(s)
-
-
- -
-
- -
4782
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem026.html b/ipython/html/EulerProblem026.html index c79e321..1ab58e9 100644 --- a/ipython/html/EulerProblem026.html +++ b/ipython/html/EulerProblem026.html @@ -1,9 +1,9 @@ + - + EulerProblem026 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 26

A unit fraction contains 1 in the numerator. The decimal representation of the unit fractions with denominators 2 to 10 are given:

- +

Euler Problem 26

Back to overview.

A unit fraction contains 1 in the numerator. The decimal representation of the unit fractions with denominators 2 to 10 are given:

1/2  =  0.5
 1/3  =  0.(3)
 1/4  =  0.25
@@ -11788,7 +11782,6 @@ div#notebook {
 1/10    =   0.1

Where 0.1(6) means 0.166666..., and has a 1-digit recurring cycle. It can be seen that 1/7 has a 6-digit recurring cycle.

Find the value of d < 1000 for which 1/d contains the longest recurring cycle in its decimal fraction part.

-
@@ -11798,15 +11791,14 @@ div#notebook {

The trick here is to identify a cycle. The easiest way I see to do this is to memorize the remainders. If we have a remainder that we occurred previously there is a cycle.

Let's consider 1/3. The initial remainder is 10. For ten divided by three the new remainder is again ten (or one times ten). So we have a one-cycle of 3.

-
-
In [1]:
+
In [1]:
-
+
def get_cycle_count(nominator, denominator):
     from itertools import count
     assert(nominator == 1)
@@ -11829,60 +11821,44 @@ div#notebook {
 assert(get_cycle_count(1, 10) == 0)
 assert(get_cycle_count(1, 6) == 1)
 
-
-

This is a simple divison algorithm. The only special thing is the remainder and that we remember when it occurs the first time. If a remainder occurrs for the second time we substract the position and thus have the lenght of the cycle. With this solution we should be efficient enough to brute force.

-
-
In [2]:
+
In [2]:
-
+
s = max([(get_cycle_count(1, i), i)for i in range(1, 1000)])
 s = s[1]
 assert(s == 983)
 print(s)
 
-
-
- -
-
- -
983
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem027.html b/ipython/html/EulerProblem027.html index 37b864a..f073e49 100644 --- a/ipython/html/EulerProblem027.html +++ b/ipython/html/EulerProblem027.html @@ -1,9 +1,9 @@ + - + EulerProblem027 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 27

Euler discovered the remarkable quadratic formula:

+

Euler Problem 27

Back to overview.

Euler discovered the remarkable quadratic formula:

$n^2 + n + 41$

It turns out that the formula will produce 40 primes for the consecutive integer values 0≤n≤39. However, when $n=40$, $40^2 + 40 + 41 = 40(40+1)+41$ is divisible by $41$, and certainly when $n=41,41^2+41+41$ is clearly divisible by 41.

The incredible formula $n^2−79n+1601$ was discovered, which produces 80 primes for the consecutive values 0≤n≤79. The product of the coefficients, $−79$ and $1601$, is $−126479$.

@@ -11783,7 +11778,6 @@ div#notebook {

$n^2 + an +b$, where |a|<1000 and |b|≤1000

where |n| is the modulus/absolute value of n e.g. |11|=11 and |−4|=4.

Find the product of the coefficients, a and b, for the quadratic expression that produces the maximum number of primes for consecutive values of n, starting with n=0.

-
@@ -11804,15 +11798,14 @@ div#notebook {

$p^2 - p + 41 >= 1000$ True for $\forall p \in \mathbb{N}$

So now we only have to check for the values p in range(-30, 32). Alternatively, for the example $p = 40$ was used, maybe the next smaller value $p = 31$ yields the correct solution:

$s = a\times b = (-2 * 31 + 1) * (31^2 - 31 + 41) = -61 \times 971 = -59231$

-
-
In [1]:
+
In [1]:
-
+
from functools import lru_cache
 
 @lru_cache(maxsize=1000)
@@ -11847,37 +11840,21 @@ div#notebook {
 assert(s == -59231)
 s
 
-
-
- -
-
Out[1]:
- - - -
-59231
- -
-
-
-
-
+
+
+
- - - - diff --git a/ipython/html/EulerProblem028.html b/ipython/html/EulerProblem028.html index ef583ad..58217f7 100644 --- a/ipython/html/EulerProblem028.html +++ b/ipython/html/EulerProblem028.html @@ -1,9 +1,9 @@ + - + EulerProblem028 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 28

Starting with the number 1 and moving to the right in a clockwise direction a 5 by 5 spiral is formed as follows:

- +

Euler Problem 28

Back to overview.

Starting with the number 1 and moving to the right in a clockwise direction a 5 by 5 spiral is formed as follows:

21 22 23 24 25
 20  7  8  9 10
 19  6  1  2 11
@@ -11785,7 +11779,6 @@ div#notebook {
 

$1 + 3 + 5 + 7 + 9 + 13 + 17 + 21 + 25 = 101$

It can be verified that the sum of the numbers on the diagonals is 101.

What is the sum of the numbers on the diagonals in a 1001 by 1001 spiral formed in the same way?

-
@@ -11794,15 +11787,14 @@ div#notebook {

When we know the corner of a certain spiral we can calculate it's total like $f_n = 4 c_n + 6 (n - 1)$. We then only have to update the corner value for each spiral.

-
-
In [1]:
+
In [1]:
-
+
total = 1
 current_corner = 3
 
@@ -11812,45 +11804,31 @@ div#notebook {
 
 s = total
 
-
-
-
In [2]:
+
In [2]:
-
+
assert(s == 669171001)
 s
 
-
-
- -
-
Out[2]:
- - - -
669171001
- -
-
- +
@@ -11862,50 +11840,33 @@ div#notebook {

$c_n = (n - 1)^2 - (n - 2) = n^2 - 2n + 1 - n + 2 = n^2 - 3n + 3$.

Now, we can insert $c_n$ into $f_n$ which gives as the sum of corners for the nth spiral:

$f_n = 4n^2 - 12n + 12 + 6n - 6 = 4n^2 - 6n + 6$

-
-
In [3]:
+
In [3]:
-
+
s = 1 + sum([4 * n * n - 6 * n + 6 for n in range(3, 1002, 2)])
 assert(s == 669171001)
 s
 
-
-
- -
-
Out[3]:
- - - -
669171001
- -
-
-
-
-
+
+
+
- - - - diff --git a/ipython/html/EulerProblem029.html b/ipython/html/EulerProblem029.html index 6e03d86..a05f522 100644 --- a/ipython/html/EulerProblem029.html +++ b/ipython/html/EulerProblem029.html @@ -1,9 +1,9 @@ + - + EulerProblem029 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 29

Consider all integer combinations of ab for 2 ≤ a ≤ 5 and 2 ≤ b ≤ 5:

+

Euler Problem 29

Back to overview.

Consider all integer combinations of ab for 2 ≤ a ≤ 5 and 2 ≤ b ≤ 5:

$2^2=4, 2^3=8, 2^4=16, 2^5=32$

$3^2=9, 3^3=27, 3^4=81, 3^5=243$

$4^2=16, 4^3=64, 4^4=256, 4^5=1024$

@@ -11783,48 +11778,34 @@ div#notebook {

If they are then placed in numerical order, with any repeats removed, we get the following sequence of 15 distinct terms:

$4, 8, 9, 16, 25, 27, 32, 64, 81, 125, 243, 256, 625, 1024, 3125$

How many distinct terms are in the sequence generated by $a^b$ for $2 ≤ a ≤ 100$ and $2 ≤ b ≤ 100$?

-
-
In [1]:
+
In [1]:
-
+
s = len(set([a**b for a in range(2, 101) for b in range(2, 101)]))
 assert(s == 9183)
 print(s)
 
-
-
- -
-
- -
9183
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem030.html b/ipython/html/EulerProblem030.html index c6dedb8..13b2d62 100644 --- a/ipython/html/EulerProblem030.html +++ b/ipython/html/EulerProblem030.html @@ -1,9 +1,9 @@ + - + EulerProblem030 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 30

Surprisingly there are only three numbers that can be written as the sum of fourth powers of their digits:

+

Euler Problem 30

Back to overview.

Surprisingly there are only three numbers that can be written as the sum of fourth powers of their digits:

$1634 = 1^4 + 6^4 + 3^4 + 4^4$

$8208 = 8^4 + 2^4 + 0^4 + 8^4$

$9474 = 9^4 + 4^4 + 7^4 + 4^4$

As $1 = 1^4$ is not a sum it is not included.

The sum of these numbers is $1634 + 8208 + 9474 = 19316$.

Find the sum of all the numbers that can be written as the sum of fifth powers of their digits.

-
@@ -11791,15 +11785,14 @@ div#notebook {

This is an eays brute force. We look up the fifth powers.

-
-
In [7]:
+
In [7]:
-
+
fifth_power_lookup = {str(i): i**5 for i in range(0,10)}
 
 def is_number_sum_of_fiths_powers_of_digits(n):
@@ -11809,35 +11802,22 @@ div#notebook {
 print(s)
 assert(s == 443839)
 
-
-
- -
-
- -
443839
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem031.html b/ipython/html/EulerProblem031.html index 2fa3153..bb26a9c 100644 --- a/ipython/html/EulerProblem031.html +++ b/ipython/html/EulerProblem031.html @@ -1,9 +1,9 @@ + - + EulerProblem031 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 31

In England the currency is made up of pound, £, and pence, p, and there are eight coins in general circulation:

+

Euler Problem 31

Back to overview.

In England the currency is made up of pound, £, and pence, p, and there are eight coins in general circulation:

1p, 2p, 5p, 10p, 20p, 50p, £1 (100p) and £2 (200p).

It is possible to make £2 in the following way:

1×£1 + 1×50p + 2×20p + 1×5p + 1×2p + 3×1p

How many different ways can £2 be made using any number of coins?

-
@@ -11789,50 +11783,40 @@ div#notebook {

Let's do it non-recursive. Tricky part is to use ceil, otherwise we get wrong ranges for example for $\frac{50}{20}$.

-
-
In [1]:
+
In [1]:
-
+
from math import ceil
 
 print(list(range(50 // 20)))
 print(list(range(ceil(50 / 20))))
 
-
-
- -
-
- -
[0, 1]
 [0, 1, 2]
 
-
-
-
In [2]:
+
In [2]:
-
+
from math import ceil
 
 r = 200
@@ -11873,49 +11857,34 @@ div#notebook {
 
 s = c
 
-
-
-
In [3]:
+
In [3]:
-
+
print(s)
 assert(s == 73682)
 
-
-
- -
-
- -
73682
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem032.html b/ipython/html/EulerProblem032.html index eecf2cb..f9ca082 100644 --- a/ipython/html/EulerProblem032.html +++ b/ipython/html/EulerProblem032.html @@ -1,9 +1,9 @@ + - + EulerProblem032 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 32

We shall say that an n-digit number is pandigital if it makes use of all the digits 1 to n exactly once; for example, the 5-digit number, 15234, is 1 through 5 pandigital.

+

Euler Problem 32

Back to overview.

We shall say that an n-digit number is pandigital if it makes use of all the digits 1 to n exactly once; for example, the 5-digit number, 15234, is 1 through 5 pandigital.

The product 7254 is unusual, as the identity, 39 × 186 = 7254, containing multiplicand, multiplier, and product is 1 through 9 pandigital.

Find the sum of all products whose multiplicand/multiplier/product identity can be written as a 1 through 9 pandigital.

HINT: Some products can be obtained in more than one way so be sure to only include it once in your sum.

-
@@ -11788,15 +11782,14 @@ div#notebook {

We start by thinking about how many digits are used for multiplicand/multiplier/product. Obviously, the product must have more then three digits. Can it have more then 4 digits? Obviously it can because then there are only four digits for multiplicand and multiplier which is always smaller than ten thousand. So our product must be in the form $12 \cdot 345 = 5789$. This makes the rest very easy in Python.

-
-
In [1]:
+
In [1]:
-
+
from itertools import permutations
 
 def is_solution(s):
@@ -11808,45 +11801,29 @@ div#notebook {
         return c
     return 0
 
-assert(is_solution("391867254") == 7254)
-assert(is_solution("391867245") == 0)
+assert(is_solution("391867254") == 7254)
+assert(is_solution("391867245") == 0)
 
 
-s = sum(set([is_solution("".join(p)) for p in permutations("123456789")]))
+s = sum(set([is_solution("".join(p)) for p in permutations("123456789")]))
 assert(s == 45228)
 s
 
-
-
- -
-
Out[1]:
- - - -
45228
- -
-
-
-
-
+
+
+
- - - - diff --git a/ipython/html/EulerProblem033.html b/ipython/html/EulerProblem033.html index 2109a9b..4a43910 100644 --- a/ipython/html/EulerProblem033.html +++ b/ipython/html/EulerProblem033.html @@ -1,9 +1,9 @@ + - + EulerProblem033 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 33

The fraction 49/98 is a curious fraction, as an inexperienced mathematician in attempting to simplify it may incorrectly believe that 49/98 = 4/8, which is correct, is obtained by cancelling the 9s.

+

Euler Problem 33

Back to overview.

The fraction 49/98 is a curious fraction, as an inexperienced mathematician in attempting to simplify it may incorrectly believe that 49/98 = 4/8, which is correct, is obtained by cancelling the 9s.

We shall consider fractions like, 30/50 = 3/5, to be trivial examples.

There are exactly four non-trivial examples of this type of fraction, less than one in value, and containing two digits in the numerator and denominator.

If the product of these four fractions is given in its lowest common terms, find the value of the denominator.

-
@@ -11788,15 +11782,14 @@ div#notebook {

We start write a function which checks if a number is curios and then brute force.

-
-
In [21]:
+
In [21]:
-
+
def is_curious(n, d):
     assert(len(str(n)) == 2 and len(str(d)) == 2)
     if n == d:
@@ -11804,8 +11797,8 @@ div#notebook {
     for i in range(1, 10):
         if str(i) in str(n) and str(i) in str(d):
             try:
-                n_ = int(str(n).replace(str(i), ""))
-                d_ = int(str(d).replace(str(i), ""))
+                n_ = int(str(n).replace(str(i), ""))
+                d_ = int(str(d).replace(str(i), ""))
             except ValueError:
                 return False
             try:
@@ -11818,97 +11811,73 @@ div#notebook {
 assert(is_curious(49, 98) == True)
 assert(is_curious(30, 50) == False)
 
-
-
-
In [25]:
+
In [25]:
-
+
fs = [(n, d) for n in range(10, 100) for d in range(n, 100) if is_curious(n, d)]
 fs
 
-
-
- -
-
Out[25]:
- - - -
[(16, 64), (19, 95), (26, 65), (49, 98)]
- -
-
- +
-
In [32]:
+
In [32]:
-
+
n = 1
 d = 1
 for n_, d_ in fs:
     n *= n_
     d *= d_
 
-print("{}/{}".format(n, d))
+print("{}/{}".format(n, d))
 
-
-
- -
-
- -
387296/38729600
 
-
-

Now we can see that the solution is $100$. But actually it would be nice to calculate the GCD.

-
-
In [40]:
+
In [40]:
-
+
def gcd_euclid(a, b):
     if a == b:
         return a
@@ -11923,37 +11892,21 @@ div#notebook {
 assert(s == 100)
 s
 
-
-
- -
-
Out[40]:
- - - -
100
- -
-
-
-
-
+
+
+
- - - - diff --git a/ipython/html/EulerProblem034.html b/ipython/html/EulerProblem034.html index 1e1c333..e76ef57 100644 --- a/ipython/html/EulerProblem034.html +++ b/ipython/html/EulerProblem034.html @@ -1,9 +1,9 @@ + - + EulerProblem034 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 34

145 is a curious number, as 1! + 4! + 5! = 1 + 24 + 120 = 145.

+

Euler Problem 34

Back to overview.

145 is a curious number, as 1! + 4! + 5! = 1 + 24 + 120 = 145.

Find the sum of all numbers which are equal to the sum of the factorial of their digits.

Note: as 1! = 1 and 2! = 2 are not sums they are not included.

-
@@ -11787,15 +11781,14 @@ div#notebook {

The algorithm for checking if a number is curious should be efficient. The more difficult thing is to select the upper bound for the brute force. It can be seen that $9 999 999 < 9! * 7$. Hence we can select $10^7$ as our bound.

-
-
In [1]:
+
In [1]:
-
+
from math import factorial
 
 def is_curious(n):
@@ -11804,64 +11797,44 @@ div#notebook {
 
 assert(is_curious(145) == True)
 
-
-
-
In [2]:
+
In [2]:
-
+
s = sum([n for n in range(3, 10**7) if is_curious(n)])
 
-
-
-
In [3]:
+
In [3]:
-
+
assert(s == 40730)
 s
 
-
-
- -
-
Out[3]:
- - - -
40730
- -
-
-
-
-
+
+
+
- - - - diff --git a/ipython/html/EulerProblem035.html b/ipython/html/EulerProblem035.html index d1ff1a6..dddf93b 100644 --- a/ipython/html/EulerProblem035.html +++ b/ipython/html/EulerProblem035.html @@ -1,9 +1,9 @@ + - + EulerProblem035 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 35

The number, 197, is called a circular prime because all rotations of the digits: 197, 971, and 719, are themselves prime.

+

Euler Problem 35

Back to overview.

The number, 197, is called a circular prime because all rotations of the digits: 197, 971, and 719, are themselves prime.

There are thirteen such primes below 100: 2, 3, 5, 7, 11, 13, 17, 31, 37, 71, 73, 79, and 97.

How many circular primes are there below one million?

-
@@ -11787,15 +11781,14 @@ div#notebook {

First we get all primes into a look-up table. Then we iterate them and check whether they are circular.

-
-
In [1]:
+
In [1]:
-
+
def get_primes_smaller(number):
     primes = []
     prospects = [n for n in range(2, number)]
@@ -11809,17 +11802,15 @@ div#notebook {
 
 ps = get_primes_smaller(1000000)
 
-
-
-
In [2]:
+
In [2]:
-
+
def get_combinations(xs):
     if not xs:
         return []
@@ -11832,85 +11823,71 @@ div#notebook {
             rs.append(xs[i] + ys)
     return rs
 
-assert(get_combinations("ab") == ["ab", "ba"])
+assert(get_combinations("ab") == ["ab", "ba"])
 
-
-
-
In [3]:
+
In [3]:
-
+
from itertools import permutations
 prime_set = set(ps)
 
 def is_circular(p):
     cs = permutations(str(p))
     for c in cs:
-        if not int("".join(c)) in prime_set:
+        if not int("".join(c)) in prime_set:
             return False
     return True
 
-assert(is_circular("2") == True)
-assert(is_circular("11") == True)
-assert(is_circular("47") == False)
+assert(is_circular("2") == True)
+assert(is_circular("11") == True)
+assert(is_circular("47") == False)
 
-
-
-
In [4]:
+
In [4]:
-
+
s = len([p for p in ps if is_circular(p)])
-print("False solution {}".format(s))
+print("False solution {}".format(s))
 
-
-
- -
-
- -
False solution 22
 
-
-

We did not read the problem properly. Cycles are obviously not the same as permutations. If we change that we should get the solution in no time.

-
-
In [5]:
+
In [5]:
-
+
def cyles(xs):
     if len(xs) <= 1:
         return xs
@@ -11921,55 +11898,37 @@ div#notebook {
 def is_circular(p):
     cs = cyles(str(p))
     for c in cs:
-        if not int("".join(c)) in prime_set:
+        if not int("".join(c)) in prime_set:
             return False
     return True
 
-
-
-
In [6]:
+
In [6]:
-
+
s = len([p for p in ps if is_circular(p)])
 s
 
-
-
- -
-
Out[6]:
- - - -
55
- -
-
-
-
-
+
+
+
- - - - diff --git a/ipython/html/EulerProblem036.html b/ipython/html/EulerProblem036.html index afcf38f..23c801c 100644 --- a/ipython/html/EulerProblem036.html +++ b/ipython/html/EulerProblem036.html @@ -1,9 +1,9 @@ + - + EulerProblem036 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 36

The decimal number, 585 = $1001001001_2$ (binary), is palindromic in both bases.

+

Euler Problem 36

Back to overview.

The decimal number, 585 = $1001001001_2$ (binary), is palindromic in both bases.

Find the sum of all numbers, less than one million, which are palindromic in base 10 and base 2.

(Please note that the palindromic number, in either base, may not include leading zeros.)

-
@@ -11787,15 +11781,14 @@ div#notebook {

This looks like an easy problem to me. Like really easy. Should we try to brute force first?

-
-
In [1]:
+
In [1]:
-
+
def is_palindrome_decimal(n):
     return str(n) == str(n)[::-1]
 
@@ -11803,17 +11796,15 @@ div#notebook {
 assert(is_palindrome_decimal(2) == True)
 assert(is_palindrome_decimal(2322) == False)
 
-
-
-
In [2]:
+
In [2]:
-
+
def is_palindrome_binary(n):
     s = str(bin(n)[2:])
     return s == s[::-1]
@@ -11821,61 +11812,44 @@ div#notebook {
 assert(is_palindrome_binary(585) == True)
 assert(is_palindrome_binary(3) == True)
 
-
-
-
In [3]:
+
In [3]:
-
+
s = sum([i for i in range(1000000) if is_palindrome_decimal(i) and is_palindrome_binary(i)])
 
-
-
-
In [4]:
+
In [4]:
-
+
print(s)
 
-
-
- -
-
- -
872187
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem037.html b/ipython/html/EulerProblem037.html index 05a31dc..691b05e 100644 --- a/ipython/html/EulerProblem037.html +++ b/ipython/html/EulerProblem037.html @@ -1,9 +1,9 @@ + - + EulerProblem037 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 37

The number 3797 has an interesting property. Being prime itself, it is possible to continuously remove digits from left to right, and remain prime at each stage: 3797, 797, 97, and 7. Similarly we can work from right to left: 3797, 379, 37, and 3.

+

Euler Problem 37

Back to overview.

The number 3797 has an interesting property. Being prime itself, it is possible to continuously remove digits from left to right, and remain prime at each stage: 3797, 797, 97, and 7. Similarly we can work from right to left: 3797, 379, 37, and 3.

Find the sum of the only eleven primes that are both truncatable from left to right and right to left.

NOTE: 2, 3, 5, and 7 are not considered to be truncatable primes.

-
@@ -11788,15 +11782,14 @@ div#notebook {

Okay, I would say we start with one digit and work ourselves up. I will start with implementing a function that takes all current solutions (with one digit for example) and then tests all possible new solutions (aka all two digit primes) if the can be truncated to the one digit solutions.

This was complicated. Let's formulate it clearer. We write a function that takes a list of numbers and tests whether they are left/right trunctable to another list of numbers.

-
-
In [1]:
+
In [1]:
-
+
def get_truncatable_numbers(numbers, targets):
     s = set(targets)
     r = []
@@ -11809,26 +11802,23 @@ div#notebook {
 
 assert(get_truncatable_numbers([37, 77, 83], [2, 3, 5, 7]) == [37, 77])
 
-
-

The next function returns a list of all primes with a certain number of digits n. We gonna reuse the sieve from problem 21.

-
-
In [2]:
+
In [2]:
-
+
def sieve_of_eratosthenes(limit):
     primes = []
     prospects = [n for n in range(2, limit)]
@@ -11852,26 +11842,23 @@ div#notebook {
 assert(get_primes_with_n_digits(1) == [2, 3, 5, 7])
 assert(len(get_primes_with_n_digits(2)) == 21)
 
-
-

Now we simply start with all one digit primes and work our way up using the two functions we have created. On the way up we add the numbers to our result list. For example, 97 is already a valid solution even though it is also the subset of a solution with more digits.

-
-
In [3]:
+
In [3]:
-
+
digits = 1
 solutions = get_primes_with_n_digits(digits)
 results = []
@@ -11884,44 +11871,34 @@ div#notebook {
     
 print(results)
 
-
-
- -
-
- -
[23, 37, 53, 73, 373]
 
-
-

This are not the eleven numbers we are looking for. The mistake we made is to not differentiate between left truncatable numbers and right truncatable numbers. For example, 397 is truncatable from the left, but not from the right and is still part of a solution. What we want to do is to work up from both directions and then compute the subset. Hence we write to new functions to check for all truncatable numbers from either left or right and then apply the algorithm from above to both of them.

-
-
In [4]:
+
In [4]:
-
+
def get_truncatable_numbers_right(numbers, targets):
     s = set(targets)
     return [n for n in numbers if int(str(n)[:-1]) in s]
@@ -11930,26 +11907,23 @@ div#notebook {
     s = set(targets)
     return [n for n in numbers if int(str(n)[1:]) in s]
 
-
-

Let's redo the alogirthm.

-
-
In [5]:
+
In [5]:
-
+
digits = 1
 solutions = get_primes_with_n_digits(digits)
 results_left = []
@@ -11976,45 +11950,35 @@ div#notebook {
     
 print(results_right)
 
-
-
- -
-
- -
[]
 []
 
-
-

I added the terminate symbols because this algorithm did not even terminate. This means there are fairly big primes in either direction. We change the approach from bottom up into the other direction. Let's get all primes till a certain value and just check for them. Aka brute force. For this purpose we write a function that takes a number and checks if it is truncatable in both directions.

-
-
In [6]:
+
In [6]:
-
+
primes_till_10000 = set(sieve_of_eratosthenes(10000))
 
 def is_right_truncatable(number, targets):
@@ -12048,67 +12012,54 @@ div#notebook {
 
 assert(is_truncatable(3797, primes_till_10000))
 
-
-

Let's just go for a brute force till 10k and see what we get.

-
-
In [7]:
+
In [7]:
-
+
s = [p for p in primes_till_10000 if is_truncatable(p, primes_till_10000)]
 print(s)
 
-
-
- -
-
- -
[2, 3, 5, 7, 23, 37, 53, 73, 313, 317, 373, 797, 3137, 3797]
 
-
-

The one digit numbers are not relevant but this means we got only ten solutions. So we actually have to try all numbers till $10^{6}$. As it turned out we actually have to add one more digit. This is really ugly brute force. I do not like it. But seems like we got a solution.

-
-
In [8]:
+
In [8]:
-
+
primes_till_100000 = set(sieve_of_eratosthenes(1000000))
 s = [p for p in primes_till_100000 if is_truncatable(p, primes_till_100000)]
 print(s)
@@ -12116,36 +12067,23 @@ div#notebook {
 s = sum(s[4:])
 assert(s == 748317)
 
-
-
- -
-
- -
[2, 3, 5, 7, 23, 37, 53, 73, 313, 317, 373, 797, 3137, 3797, 739397]
 748317
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem038.html b/ipython/html/EulerProblem038.html index cc77ec3..826619b 100644 --- a/ipython/html/EulerProblem038.html +++ b/ipython/html/EulerProblem038.html @@ -1,9 +1,9 @@ + - + EulerProblem038 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 38

Take the number 192 and multiply it by each of 1, 2, and 3:

+

Euler Problem 38

Back to overview.

Take the number 192 and multiply it by each of 1, 2, and 3:

$192 \times 1 = 192$

$192 \times 2 = 384$

$192 \times 3 = 576$

By concatenating each product we get the 1 to 9 pandigital, 192384576. We will call 192384576 the concatenated product of 192 and (1,2,3)

The same can be achieved by starting with 9 and multiplying by 1, 2, 3, 4, and 5, giving the pandigital, 918273645, which is the concatenated product of 9 and (1,2,3,4,5).

What is the largest 1 to 9 pandigital 9-digit number that can be formed as the concatenated product of an integer with (1,2, ... , n) where n > 1?

-
@@ -11791,46 +11785,42 @@ div#notebook {

Let's start by implementing a function which can calculate the concatenated product of a number based on a given $n$.

-
-
In [1]:
+
In [1]:
-
+
def get_concatenated_product_of(number, n):
     number = int(number)
-    return "".join(str(number * (i + 1)) for i in range(n))
+    return "".join(str(number * (i + 1)) for i in range(n))
 
-assert(get_concatenated_product_of(9, 5) == "918273645")
-assert(get_concatenated_product_of(192, 3) == "192384576")
+assert(get_concatenated_product_of(9, 5) == "918273645")
+assert(get_concatenated_product_of(192, 3) == "192384576")
 
-
-

Next we need a function that can check if a number is pandigital for the numbers from 1 to 9. The idea is that we generate a validation array for the numbers 1 to 9. Each number maps to a field in the array and we initialize the array with zeros. We then iterate over the input number and increment the respective validation field by one. Afterwards we check if each field in the validation array is one in which case the number is n-pandigital. Otherwise, it is not.

-
-
In [2]:
+
In [2]:
-
+
def is_pandigital(number, n=9):
     number_str = str(number)
     validation_array = [0 for _ in range(n)]
-    if "0" in number_str:
+    if "0" in number_str:
         return False
     for digit in number_str:
         validation_array[ord(digit) - 49] += 1
@@ -11839,25 +11829,22 @@ div#notebook {
             return False
     return True
 
-assert(is_pandigital("012345678") == False)
-assert(is_pandigital("123") == False)
-assert(is_pandigital("9") == False)
-assert(is_pandigital("123568") == False)
-assert(is_pandigital("987", 9) == False)
-assert(is_pandigital("918273645"))
+assert(is_pandigital("012345678") == False)
+assert(is_pandigital("123") == False)
+assert(is_pandigital("9") == False)
+assert(is_pandigital("123568") == False)
+assert(is_pandigital("987", 9) == False)
+assert(is_pandigital("918273645"))
 
-
-

This example shows how important it is to add little tests even for simple programs like this. The first example is certainly not 1 to 9 pandigital, but because of negative array indexing in Python it qualifies as True. We solved this problem by adding a simple check for a "0" in the number_str.

-
@@ -11866,19 +11853,18 @@ div#notebook {

The next step is to check whether a number has the potential to become a 1 to 9 pandigital. The algorithm is essentially the same except this time we return False only if a field in the validation array is greater than 1. This means at least one digit occurs multiple times. Otherwise, the array has still potential to become a pandigital number.

-
-
In [3]:
+
In [3]:
-
+
def could_be_pandigital(number, n=9):
     number_str = str(number)
     validation_array = [0 for _ in range(n)]
-    if "0" in number_str:
+    if "0" in number_str:
         return False
     for digit in number_str:
         validation_array[ord(digit) - 49] += 1
@@ -11887,35 +11873,32 @@ div#notebook {
             return False
     return True
 
-assert(could_be_pandigital("012345678") == False)
-assert(could_be_pandigital("123") == True)
-assert(could_be_pandigital("9") == True)
-assert(could_be_pandigital("123568") == True)
-assert(could_be_pandigital("987", 9) == True)
-assert(could_be_pandigital("918273645"))
-assert(could_be_pandigital("98233") == False)
-assert(could_be_pandigital("1223") == False)
+assert(could_be_pandigital("012345678") == False)
+assert(could_be_pandigital("123") == True)
+assert(could_be_pandigital("9") == True)
+assert(could_be_pandigital("123568") == True)
+assert(could_be_pandigital("987", 9) == True)
+assert(could_be_pandigital("918273645"))
+assert(could_be_pandigital("98233") == False)
+assert(could_be_pandigital("1223") == False)
 
-
-

The next function we want is one which checks if a certain number can actually create a concatenated pandigital product of an integer with (1,2, ... , n) where n > 1. For this function we can use all function which we have implemented to this point. We take a number and do a simple brute force starting with n = 2. We return False once the concatenated product cannot be a pandigital anymore. We use the two given examples as tests.

-
-
In [4]:
+
In [4]:
-
+
def can_build_concatenated_pandigital_product(number):
     number_str = str(number)
     for n in range(2, 9):
@@ -11924,152 +11907,116 @@ div#notebook {
             return concatenated_product
         if could_be_pandigital(concatenated_product) == False:
             return False
-    raise Exception("If we got here we have a bug.")
+    raise Exception("If we got here we have a bug.")
 
-assert(can_build_concatenated_pandigital_product(9) == "918273645")
-assert(can_build_concatenated_pandigital_product(192) == "192384576")
+assert(can_build_concatenated_pandigital_product(9) == "918273645")
+assert(can_build_concatenated_pandigital_product(192) == "192384576")
 
-
-

From here on it is just a matter of bruteforcing. We know that the base number of a higher concatenated pandigital product has to start with a 9. Also we know that the base number cannot have more than 5 digits because $10000 \times 1, 10000 \times 2 = 1000020000" has already more digits than a potential solution. This means we create a list of possible solutions first.

-
-
In [5]:
+
In [5]:
-
+
possible_solutions = [i for i in range(1, 10000)
-                      if str(i).startswith("9")
-                      if not "0" in str(i)
+                      if str(i).startswith("9")
+                      if not "0" in str(i)
                       if could_be_pandigital(i)]
 
-print("Number of possible solutions: {}".format(len(possible_solutions)))
+print("Number of possible solutions: {}".format(len(possible_solutions)))
 
-
-
- -
-
- -
Number of possible solutions: 401
 
-
-

Since this number is actually small enough we filter all base numbers which can produce a concatenated pandigital product.

-
-
In [6]:
+
In [6]:
-
+
possible_solutions = [s for s in possible_solutions
                       if can_build_concatenated_pandigital_product(s)]
 
-print("Number of possible solutions: {}".format(len(possible_solutions)))
+print("Number of possible solutions: {}".format(len(possible_solutions)))
 
-
-
- -
-
- -
Number of possible solutions: 4
 
-
-

Finally, calculate the actual product and print the highest one.

-
-
In [7]:
+
In [7]:
-
+
s = max(map(int, map(can_build_concatenated_pandigital_product, possible_solutions)))
 assert(s == 932718654)
 print(s)
 
-
-
- -
-
- -
932718654
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem039.html b/ipython/html/EulerProblem039.html index 3a5c672..3e461ba 100644 --- a/ipython/html/EulerProblem039.html +++ b/ipython/html/EulerProblem039.html @@ -1,9 +1,9 @@ + - + EulerProblem039 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 39

If p is the perimeter of a right angle triangle with integral length sides, {a,b,c}, there are exactly three solutions for p = 120.

+

Euler Problem 39

Back to overview.

If p is the perimeter of a right angle triangle with integral length sides, {a,b,c}, there are exactly three solutions for p = 120.

$\{20,48,52\}, \{24,45,51\}, \{30,40,50\}$

For which value of p ≤ 1000, is the number of solutions maximised?

-
@@ -11787,15 +11781,14 @@ div#notebook {

We are looking for right angle triangles so Pythagoras' theorem $a^2 + b^2 = c^2$ can be used. Also it must be true that $a <= b <= c$ is true for every solution. Let's start with a function that tests the given examples.

-
-
In [13]:
+
In [13]:
-
+
def is_right_angle_triangle(a, b, c, p):
     if a + b + c != p:
         return False
@@ -11808,26 +11801,23 @@ div#notebook {
     assert(is_right_angle_triangle(*g))
 assert(is_right_angle_triangle(29, 41, 50, 120) == False)
 
-
-

This seems bruteforceable. Let's try to find the solutions for p = 120.

-
-
In [16]:
+
In [16]:
-
+
def brute_force(p):
     solutions = [(a,b, p - a - b)
         for b in range(1, p // 2 + 1)
@@ -11838,99 +11828,73 @@ div#notebook {
 
 print(brute_force(120))
 
-
-
- -
-
- -
[(30, 40, 50), (24, 45, 51), (20, 48, 52)]
 
-
-

Looks good. Let's try for all $p <= 1000$.

-
-
In [18]:
+
In [18]:
-
+
solutions = [(len(brute_force(p)), p) for p in range(1, 1001)]
 
-
-

Well, not too fast, but also not too slow. Let's get the max and we have our solution.

-
-
In [24]:
+
In [24]:
-
+
s, p = max(solutions)
 print(p)
 assert(p == 840)
 
-
-
- -
-
- -
840
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem040.html b/ipython/html/EulerProblem040.html index f0e1ae5..8ef0ced 100644 --- a/ipython/html/EulerProblem040.html +++ b/ipython/html/EulerProblem040.html @@ -1,9 +1,9 @@ + - + EulerProblem040 - - - - - - + - - - + + - + -
-
- +
+
-

Champernowne's constant (Euler Problem 40)

https://projecteuler.net/problem=40

+

Champernowne's constant (Euler Problem 40)

Back to overview.

https://projecteuler.net/problem=40

An irrational decimal fraction is created by concatenating the positive integers:

-
0.123456789101112131415161718192021...
 
 

It can be seen that the 12th digit of the fractional part is 1.

If dn represents the nth digit of the fractional part, find the value of the following expression.

$d_{1} × d_{10} × d_{100} × d_{1000} × d_{10000} × d_{100000} × d_{1000000}$

-
@@ -11793,15 +11786,14 @@ div#notebook {

I do not see why we cannot hold $8 bytes \times 10^{6} = 8 MB$ in memory.

-
-
In [1]:
+
In [1]:
-
+
def get_irrational_fraction(digits_max):
     s = []
     n = 1
@@ -11810,81 +11802,63 @@ div#notebook {
         s.append(str(n))
         digits += len(str(n))
         n += 1
-    return "".join(s)
+    return "".join(s)
 
-assert(get_irrational_fraction(20)[12] == "1")
+assert(get_irrational_fraction(20)[12] == "1")
 
 f = get_irrational_fraction(1000001)
 
-
-

Okay, we got the fractional. No we get the digits at the different positions and calculate the product. For that purpose we reuse our poduct function from problem 8.

-
-
In [2]:
+
In [2]:
-
+
def product(xs):
     from operator import mul
     from functools import reduce
     return reduce(mul, xs, 1)
 
-
-
-
In [3]:
+
In [3]:
-
+
s = product(map(int, [f[10**i - 1] for i in range(7)]))
 print(s)
 assert(s == 210)
 
-
-
- -
-
- -
210
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem041.html b/ipython/html/EulerProblem041.html index fb2aaad..ac242d6 100644 --- a/ipython/html/EulerProblem041.html +++ b/ipython/html/EulerProblem041.html @@ -1,9 +1,9 @@ + - + EulerProblem041 - - - - - - + - - - + + - + -
-
- +
+
-

Pandigital prime (Euler Problem 41)

+

Pandigital prime (Euler Problem 41)

Back to overview.

@@ -11785,28 +11780,21 @@ div#notebook {

We shall say that an n-digit number is pandigital if it makes use of all the digits 1 to n exactly once. For example, 2143 is a 4-digit pandigital and is also prime.

What is the largest n-digit pandigital prime that exists?

-
-
In [ ]:
+
In [ ]:
-
+
 
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem042.html b/ipython/html/EulerProblem042.html index 916bb7d..0773b12 100644 --- a/ipython/html/EulerProblem042.html +++ b/ipython/html/EulerProblem042.html @@ -1,9 +1,9 @@ + - + EulerProblem042 - - - - - - + - - - + + - + -
-
- +
+
-

Coded triangle numbers (Euler Problem 42)

+

Coded triangle numbers (Euler Problem 42)

Back to overview.

@@ -11784,34 +11779,26 @@ div#notebook {

The nth term of the sequence of triangle numbers is given by, $t_n = \frac{1}{2}n(n+1)$; so the first ten triangle numbers are:

-
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
 
 

By converting each letter in a word to a number corresponding to its alphabetical position and adding these values we form a word value. For example, the word value for SKY is 19 + 11 + 25 = 55 = $t_{10}$. If the word value is a triangle number then we shall call the word a triangle word.

Using words.txt (right click and 'Save Link/Target As...'), a 16K text file containing nearly two-thousand common English words, how many are triangle words? (The file is saved in the same directory as this notebook file as EulerProblem042.txt)

-
-
In [ ]:
+
In [ ]:
-
+
 
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem043.html b/ipython/html/EulerProblem043.html index 441b6fb..f7b9672 100644 --- a/ipython/html/EulerProblem043.html +++ b/ipython/html/EulerProblem043.html @@ -1,9 +1,9 @@ + - + EulerProblem043 - - - - - - + - - - + + - + -
-
- +
+
-

Sub-string divisibility (Euler Problem 43)

+

Sub-string divisibility (Euler Problem 43)

Back to overview.

@@ -11793,28 +11788,21 @@ div#notebook {

$d_7d_8d_9=728$ is divisible by 13

$d_8d_9d_{10} =289$ is divisible by 17

Find the sum of all 0 to 9 pandigital numbers with this property.

-
-
In [ ]:
+
In [ ]:
-
+
 
 
-
-
-
-
+
+
- - - - diff --git a/ipython/html/EulerProblem067.html b/ipython/html/EulerProblem067.html index 7c07edc..3d35fb5 100644 --- a/ipython/html/EulerProblem067.html +++ b/ipython/html/EulerProblem067.html @@ -1,9 +1,9 @@ + - + EulerProblem067 - - - - - - + - - - + + - + -
-
- +
+
-

Euler Problem 67

By starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom is 23.

- +

Euler Problem 67

Back to overview.

By starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom is 23.

   3
   7 4
  2 4 6
@@ -11784,7 +11778,6 @@ div#notebook {
 

That is, 3 + 7 + 4 + 9 = 23.

Find the maximum total from top to bottom in triangle.txt (right click and 'Save Link/Target As...'), a 15K text file containing a triangle with one-hundred rows.

NOTE: This is a much more difficult version of Problem 18. It is not possible to try every route to solve this problem, as there are 299 altogether! If you could check one trillion (1012) routes every second it would take over twenty billion years to check them all. There is an efficient algorithm to solve it. ;o)

-
@@ -11793,65 +11786,50 @@ div#notebook {

So let's hope our solution is good. I have saved the triangle in a file EulerProblem067.txt in the same directory as this notebook.

-
-
In [1]:
+
In [1]:
-
+
def find_greatest_path_sum_in_triangle_string(ts):
     from functools import reduce
-    xss = [list(map(int, xs.split())) for xs in ts.split("\n") if xs]
+    xss = [list(map(int, xs.split())) for xs in ts.split("\n") if xs]
     xss.reverse()
     r = lambda xs, ys: [max([xs[i] + ys[i], xs[i + 1] + ys[i]]) for i in range(len(ys))]
     return reduce(r, xss[1:], xss[0])[0]
 
-with open('EulerProblem067.txt', 'r') as f:
+with open('EulerProblem067.txt', 'r') as f:
     triangle_string = f.read()
     
 print(find_greatest_path_sum_in_triangle_string(triangle_string))
 
-
-
- -
-
- -
7273
 
-
-

Well, that was fast.

-
-
-
+
+
- - - - diff --git a/ipython/html/index.html b/ipython/html/index.html index 3bdad0e..d1e2fc9 100644 --- a/ipython/html/index.html +++ b/ipython/html/index.html @@ -1,47 +1,48 @@ - - - - - - Project Euler Solutions + + + Euler - Felix Martin + + -
-
- -
+
- +

Project Euler

+ + +
+
+
- - - - + + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + + - - + + - - - + + + + - - - + + + + - - - + + + + + - - + +
NameCompletion dateLinkTagsLinkCompletion dateTags
Problem 001Tue, 19 Aug 2014, 20:11Problem 001Tue, 19 Aug 2014, 20:11 brute force @@ -49,10 +50,11 @@
Problem 002Tue, 19 Aug 2014, 20:36Problem 002Tue, 19 Aug 2014, 20:36 fibonacci @@ -60,10 +62,11 @@
Problem 003Tue, 19 Aug 2014, 23:35Problem 003Tue, 19 Aug 2014, 23:35 prime @@ -71,10 +74,11 @@
Problem 004Wed, 20 Aug 2014, 13:27Problem 004Wed, 20 Aug 2014, 13:27 palindrome @@ -88,10 +92,11 @@
Problem 005Wed, 20 Aug 2014, 14:32Problem 005Wed, 20 Aug 2014, 14:32 reduce @@ -101,19 +106,21 @@
Problem 006Wed, 20 Aug 2014, 15:13Problem 006Wed, 20 Aug 2014, 15:13
Problem 007Wed, 20 Aug 2014, 15:40Problem 007Wed, 20 Aug 2014, 15:40 prime @@ -127,10 +134,11 @@
Problem 008Wed, 20 Aug 2014, 16:03Problem 008Wed, 20 Aug 2014, 16:03 product @@ -142,10 +150,11 @@
Problem 009Wed, 20 Aug 2014, 17:06Problem 009Wed, 20 Aug 2014, 17:06 brute force @@ -157,10 +166,11 @@
Problem 010Wed, 20 Aug 2014, 20:28Problem 010Wed, 20 Aug 2014, 20:28 primes @@ -172,10 +182,11 @@
Problem 011Sun, 31 Aug 2014, 07:39Problem 011Sun, 31 Aug 2014, 07:39 brute force @@ -191,10 +202,11 @@
Problem 012Sun, 31 Aug 2014, 17:07Problem 012Sun, 31 Aug 2014, 17:07 triangular @@ -212,10 +224,11 @@
Problem 013Sun, 31 Aug 2014, 19:03Problem 013Sun, 31 Aug 2014, 19:03 brute force @@ -225,10 +238,11 @@
Problem 014Sun, 31 Aug 2014, 19:45Problem 014Sun, 31 Aug 2014, 19:45 collatz @@ -240,10 +254,11 @@
Problem 015Sun, 31 Aug 2014, 20:05Problem 015Sun, 31 Aug 2014, 20:05 factorial @@ -253,10 +268,11 @@
Problem 016Sun, 31 Aug 2014, 20:49Problem 016Sun, 31 Aug 2014, 20:49 c @@ -266,10 +282,11 @@
Problem 017Sun, 31 Aug 2014, 21:20Problem 017Sun, 31 Aug 2014, 21:20 count @@ -281,10 +298,11 @@
Problem 018Thu, 4 Sep 2014, 20:38Problem 018Thu, 4 Sep 2014, 20:38 fold @@ -296,10 +314,11 @@
Problem 019Fri, 5 Sep 2014, 09:56Problem 019Fri, 5 Sep 2014, 09:56 weekdays @@ -313,10 +332,11 @@
Problem 020Fri, 5 Sep 2014, 10:42Problem 020Fri, 5 Sep 2014, 10:42 factorial @@ -324,10 +344,11 @@
Problem 021Fri, 5 Sep 2014, 14:39Problem 021Fri, 5 Sep 2014, 14:39 amicable @@ -341,10 +362,11 @@
Problem 022Fri, 5 Sep 2014, 15:24Problem 022Fri, 5 Sep 2014, 15:24 sorting @@ -354,10 +376,11 @@
Problem 023Thu, 5 Nov 2015, 14:48Problem 023Thu, 5 Nov 2015, 14:48 perfect number @@ -369,10 +392,11 @@
Problem 024Thu, 5 Nov 2015, 16:04Problem 024Thu, 5 Nov 2015, 16:04 permutation @@ -380,10 +404,11 @@
Problem 025Fri, 5 Sep 2014, 14:57Problem 025Fri, 5 Sep 2014, 14:57 fibonacci @@ -391,10 +416,11 @@
Problem 026Mon, 9 Nov 2015, 22:11Problem 026Mon, 9 Nov 2015, 22:11 reciprocal @@ -408,10 +434,11 @@
Problem 027Mon, 21 Aug 2017, 21:11Problem 027Mon, 21 Aug 2017, 21:11 quadratic @@ -425,10 +452,11 @@
Problem 028Wed, 23 Aug 2017, 15:54Problem 028Wed, 23 Aug 2017, 15:54 spiral @@ -438,10 +466,11 @@
Problem 029Fri, 25 Aug 2017, 10:03Problem 029Fri, 25 Aug 2017, 10:03 distinct @@ -451,10 +480,11 @@
Problem 030Fri, 25 Aug 2017, 12:13Problem 030Fri, 25 Aug 2017, 12:13 digit @@ -466,10 +496,11 @@
Problem 031Fri, 25 Aug 2017, 13:02Problem 031Fri, 25 Aug 2017, 13:02 recursion @@ -479,10 +510,11 @@
Problem 032Wed, 30 Aug 2017, 14:25Problem 032Wed, 30 Aug 2017, 14:25 pandigital @@ -492,10 +524,11 @@
Problem 033Mon, 12 Feb 2018, 17:29Problem 033Mon, 12 Feb 2018, 17:29 gcd @@ -507,10 +540,11 @@
Problem 034Mon, 12 Feb 2018, 17:57Problem 034Mon, 12 Feb 2018, 17:57 factorial @@ -520,10 +554,11 @@
Problem 035Tue, 13 Feb 2018, 09:14Problem 035Tue, 13 Feb 2018, 09:14 circular @@ -533,10 +568,11 @@
Problem 036Fri, 11 May 2018, 02:38Problem 036Fri, 11 May 2018, 02:38 palindrome @@ -546,10 +582,11 @@
Problem 037Sun, 13 May 2018, 16:46Problem 037Sun, 13 May 2018, 16:46 primes @@ -559,10 +596,11 @@
Problem 038Sat, 19 May 2018, 23:45Problem 038Sat, 19 May 2018, 23:45 concatenated @@ -574,10 +612,11 @@
Problem 039Sun, 20 May 2018, 21:16Problem 039Sun, 20 May 2018, 21:16 triangle @@ -589,10 +628,11 @@
Problem 040Sun, 20 May 2018, 00:40Problem 040Sun, 20 May 2018, 00:40 champernowne @@ -604,10 +644,11 @@
Problem 041
Problem 041 pandigital @@ -617,10 +658,11 @@
Problem 042
Problem 042 triangle @@ -630,10 +672,11 @@
Problem 043
Problem 043 pandigital @@ -643,10 +686,11 @@
Problem 067Fri, 5 Sep 2014, 07:36Problem 067Fri, 5 Sep 2014, 07:36 reduce @@ -660,20 +704,16 @@
+
- -
-
- -
- + +
- - - - - - - \ No newline at end of file diff --git a/ipython/publish.py b/ipython/publish.py index 2e78935..7fb72b9 100755 --- a/ipython/publish.py +++ b/ipython/publish.py @@ -7,6 +7,7 @@ import shutil from operator import itemgetter from collections import namedtuple from os.path import getmtime +from bs4 import BeautifulSoup import json @@ -56,6 +57,28 @@ def convert_solutions_to_html(solutions): if not os.path.isfile(html) or getmtime(html) < getmtime(s.ipynb): args = ["jupyter-nbconvert", s.ipynb, "--output-dir=html"] subprocess.call(args) + post_process(html) + + +def post_process(html): + + def tag(t, string="", children=[], **attrs): + t = BeautifulSoup("", 'html.parser').new_tag(t, **attrs) + if string: + t.string = string + for c in children: + t.append(c) + return t + + with open(html, 'r') as f: + soup = BeautifulSoup(f.read(), 'html.parser') + + soup_h1 = soup.find("h1") + soup_p = tag("p", children=[tag("a", href="/euler", string="Back to overview.")]) + soup_h1.insert_after(soup_p) + + with open(html, 'w') as f: + f.write(str(soup)) def ship_to_failx(): diff --git a/ipython/template.html b/ipython/template.html index 15a3042..7f315a8 100644 --- a/ipython/template.html +++ b/ipython/template.html @@ -1,47 +1,50 @@ - - - - - - Project Euler Solutions + + + Euler - Felix Martin + + -
-
- -
+
- +

Project Euler

+ + +
+
+
- - - - + + + {% for s in solutions %} + {% if not s.metadata.completion_date %} + + {% else %} - - + {% endif %} +
NameCompletion dateLinkTagsLinkCompletion dateTags
{{s.name}}{{s.metadata.completion_date}}{{s.name}}{{s.metadata.completion_date}} {% for t in s.metadata.tags %} {{t}} @@ -53,20 +56,16 @@
+
- -
-
- -
- + +
- - - - - - -