Blog

Euler 3

So the other night I was a bit bored and decided to do something to pass the time. I first came across Project Euler a while ago, but had never gone further than problem #1. Boredom is a great motivator and I went through problems #2 thru #9 last night and I decided to post my solutions in search of better ones. Feel free to comment with your suggestions.

Project Euler’s Problem #3 statement is —

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

What is the largest prime factor of the number 600851475143 ?

There is no need to build a list of every divisor and test each one for primality. Instead, divide each factor out as soon as it is found. This makes the remaining number smaller throughout the search.

number = 600_851_475_143
largest_factor = 1

while number % 2 == 0:
    largest_factor = 2
    number //= 2

factor = 3
while factor * factor <= number:
    while number % factor == 0:
        largest_factor = factor
        number //= factor
    factor += 2

if number > 1:
    largest_factor = number

print(largest_factor)

After removing every possible factor up to the square root of the remaining number, anything left must itself be prime. The answer is 6857, found in constant space and at most square-root time.

Euler 8

So the other night I was a bit bored and decided to do something to pass the time. I first came across Project Euler a while ago, but had never gone further than problem #1. Boredom is a great motivator and I went through problems #2 thru #9 last night and I decided to post my solutions in search of better ones. Feel free to comment with your suggestions.

Project Euler’s Problem #8 statement is —

Find the greatest product of thirteen consecutive digits in the 1000-digit number.

73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450

A sliding window avoids multiplying the same twelve digits again for every position. Zeroes need a little care because they cannot be divided back out of the running product, so the window tracks how many it contains.

number = """\
73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450
"""

digits = [int(digit) for digit in "".join(number.split())]
window_size = 13
product = 1
zeroes = 0
largest = 0

for index, digit in enumerate(digits):
    if digit == 0:
        zeroes += 1
    else:
        product *= digit

    if index >= window_size:
        outgoing = digits[index - window_size]
        if outgoing == 0:
            zeroes -= 1
        else:
            product //= outgoing

    if index >= window_size - 1 and zeroes == 0:
        largest = max(largest, product)

print(largest)

Each digit enters and leaves the product once, making this linear-time. It prints 23514624000.

Euler 7

So the other night I was a bit bored and decided to do something to pass the time. I first came across Project Euler a while ago, but had never gone further than problem #1. Boredom is a great motivator and I went through problems #2 thru #9 last night and I decided to post my solutions in search of better ones. Feel free to comment with your suggestions.

Project Euler’s Problem #7 statement is —

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 10001st prime number?

A sieve finds all the primes up to a limit in one pass. For the nth prime, n(logn+loglogn)n(\log n + \log\log n) is an upper bound when n6n \ge 6, so the sieve can be sized without guessing or repeatedly growing it.

from math import ceil, isqrt, log

n = 10_001
limit = ceil(n * (log(n) + log(log(n))))
sieve = bytearray(b"\x01") * (limit + 1)
sieve[:2] = b"\x00\x00"

for prime in range(2, isqrt(limit) + 1):
    if not sieve[prime]:
        continue

    start = prime * prime
    count = (limit - start) // prime + 1
    sieve[start : limit + 1 : prime] = b"\x00" * count

primes = (number for number, is_prime in enumerate(sieve) if is_prime)
for _ in range(n - 1):
    next(primes)

print(next(primes))

Multiples below prime * prime were already crossed out by smaller primes. The answer is 104743; for sieve limit LL, it runs in O(LloglogL)O(L\log\log L) time and O(L)O(L) space.

Why can’t people buy newer cars in Argentina?

This is part of a series of posts about Argentina and the City of Cordoba. These are little facts I wish I knew about before I came here as an expat.

One of the first things I noticed when I arrived in Cordoba, Argentina, was the amount of old cars going around. And I’m not talking about 10-year-old cars, I’m talking about 30 years or so!

You can really find some rarities such as the Citroën 3cv happily racing around town all the time. As a consequence of all that, you can also find a disproportionate amount of cars stalled on the streets, people trying to do something under the hood. It’s really amazing how many broken down cars you’ll see every day.

Citroën 3cv

I used to wonder why that was. Now I understand.

There is no credit in Argentina. Well, technically there is, but it’s so expensive that it’s as if it doesn’t exist. That’s why people normally need to buy stuff with cash upfront. Cars, of course, happen to be expensive and most people can’t save enough to buy newer cars like that. The same is true for several other goods, but cars happen to be the most visible symptom.

From time to time, coincidently around election time, the federal government creates some credit program. These programs are temporary and limited in the number of people who can apply.

And then there’s a second problem—informality. In order to avoid taxes and benefits, most companies hire people either with no documentation or with phoney pay information, e.g. if someone’s salary is, say, $1,000, the companies would register the employee as being paid $250 instead, thus being able to pay less taxes.

And thus even with those government credit programs, most people can’t even qualify as they can’t show enough income.

How can I get rid of (not so) old books?

I’m not a big believer in keeping books forever, even though I do keep some. Most books, however, I just want to read and pass along.

It just so happens that I have a ton of books that I want to get rid of. I could throw them away, but it somehow feels wrong. Also, I could donate them to some school, but considering where I live now, I assume this too will bring me one hell of a bureaucratic nightmare. Also, most of the books are either in English or Portuguese, so schools would probably not use them anyway.

With very few exceptions, all the books are either mathematics, economics, programming, or scifi. I thought I’d simply take the books to the office and give them away to anyone who’d like to have them.

But then my wife gave me an idea. Instead of taking the books and giving them outright, I started sending random emails to a mailing list with geeky questions, often related to the book topic. Whoever answers correctly first, gets the book.

This worked amazingly well.

  1. It created a fun environment for all involved. People actually want to get the answers right. Others learn by, well, learning the winning answer.

  2. For books that normally no one would care about, the fact that you have to win to get it suddenly adds value. It’s no longer a book no one wants, it now is an award.

  3. All of a sudden everybody loves me 😉

Had I just announced I had a bunch of books, people would get by, pick a few they cared about and that would have been it. No fun. So every now and then I take a few books from home and then give them away to quiz winners.

It’s actually lots of fun.