05.29.08

Project Euler: Problem 5

Posted in python tagged , , at 7:55 pm by redochre

Problem 5:

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 number that is evenly divisible by all of the numbers from 1 to 20?

A solution:

from math import ceil

def factorize(num):
    powers = []
    limit = int(ceil(float(num)/2)) # we only need to look up to num/2 for factors
    for i in range(2, limit+1):
        while num % i == 0: # ie, if i is a factor of num
            powers.append(i)
            num = num/i # take factor out of num and continue with smaller num
    if len(powers) == 0: # haven't found any factors, ie, num is prime
        powers.append(num)
    return powers

topnum = 20
master_factors = []
total = 1
for i in range(2,topnum+1):
    current_factors = factorize(i)
    while len(current_factors) != 0:
        fact = current_factors[0]
        count_difference = current_factors.count(fact)-master_factors.count(fact)
        if count_difference > 0:
            for j in range(count_difference): master_factors.append(fact)
        del current_factors[0:current_factors.count(fact)]

for i in range(len(master_factors)): total *= master_factors[i]

print total

This code seems pretty messy, there’s surely better ways to write it. For sure, the factorize function should be changed so that it only checks odd numbers (after two), that would get rid of half the iterations. After solving the problem I looked through the forum for ways others were solving it, and found this one written in Python, from user tenigmanogo:

def gcd(a, b):
while b != 0:
a, b = b, a % b
return a

def lcm(a, b):
return a*b/gcd(a, b)

print reduce(lcm, range(1, 20+1))

Definitely makes me want to learn more, and get better about looking at problems in different ways. It’s so simple! Though, with the longer solution, I now have a function that will find the prime factors of a number, which will come in handy for future problems.

4 Comments »

  1. parseidon said,

    Another short way to do it:

    def findFirstPrime(n):
    for x in range(2,n+1):
    if float(n)%x == 0:
    return x

    res = 1
    for x in range(1,20+1):
    if res%x != 0:
    n = findFirstPrime(x)
    res*= n

    print res

  2. parseidon said,

    (my bad, indenting died. Here it is with manual indenting)

    def findPrime(n):
    ..for x in range(2,n+1):
    …..if float(n)%x == 0:
    ………return x

    res = 1
    for x in range(1,20+1):
    …if res%x != 0:
    …….n = findPrime(x)
    ………..res*= n

    print res

  3. redochre said,

    Clever! It took me a while of staring at your algorithm (and working it out with paper and pencil) to see why it works, and I like it. Though it’s not a problem here, the findFirstPrime method would get pretty slow with bigger numbers, right?

    It’s great to see cleaner ways of doing things. Thank you!

  4. parseidon said,

    Yeah, it tends to get pretty slow, but given the task at hand, it was not that bad.

    I just did it according to this bit of logic:

    print 2, 2*1

    print 3, 3*(2*1)

    print 4, 2*(3*(2*1))

    print 5, 5*(2*(3*(2*1)))

    print 6, 5*(2*(3*(2*1)))

    print 7, 7*(5*(2*(3*(2*1))))

    print 8, 2*(7*(5*(2*(3*(2*1)))))

    print 9, 3*(2*(7*(5*(2*(3*(2*1))))))

    print 10, 3*(2*(7*(5*(2*(3*(2*1))))))

    where the second argument is always a number where every number smaller or equal to the first argument will work fine to give an int. Certainly not as good as the lcm/gcd way


Leave a Comment