views:

164

answers:

2

Here's my solution to Project Euler problem #5:

#include <stdio.h>
#include <stdint.h>

#define N 20

int main( int argc, char* argv[] )
{
   uint64_t r = 1;
   uint64_t i, j;

   for( i = 2; i <= N; ++i )
      if( (j = r%i) )
         r *= ( (i%j) ? i : (i/j) );

   printf( "\n%llu\n", r );

   return 0;
}

It is of O(n) efficiency. I've looked through a few pages of the official thread containing various solutions, but I didn't note any with an efficiency of O(n) or less. I wouldn't be surprised if I'm simply implementing some known solution, but if I am, I can't find it. Thoughts?

A: 

I did it with paper/pencil.

Find lcm(1, 2, ..., 20)(Least Common Multiple) of the numbers in the specified range. You could easily prove that you can reduce the above solution to:

lcm(11, 12, ..., 20)

Which is left as an exercise to the readre ;)

AraK
That's an interesting observation, but how does that answer the question?
Nikita Rybak
+5  A: 

The problem is, your algorithm isn't completely correct. For example, for 27 it returns 722820898800, while 80313433200 is smaller and also valid (divisible by 2..27).

In your loop body, you seem to do first two steps of Euclid's algorithm to find greatest common divisor. While for small numbers two steps is enough, bigger numbers require more operations (that's why recursion is used).

So, your solution can be fixed like this ('gcd' stands for greatest common divisor)

for( i = 2; i <= N; ++i )
    r *= i / gcd(i, r);
Nikita Rybak
Ah, I see! My algorithm appears to work for integers 1-26, but not 27 and above. Do you know why that is?
Matt Tardiff
@Matt why 27 and not 24 or 29? Just luck :) As for why it happens in general, I wrote a bit in my answer. For some (especially small) numbers, your way of finding GCD will work. But at 'i == 27' it fails, screwing up answer for n == 27 and above (because you build answer for _n + 1_ using an answer for _n_).
Nikita Rybak
@Nikita Just curious, what running time did your program take to calculate 27?
Fredrick Pennachi
@AsLanFromNarnia Something about 10ms, I guess :) It's like the sample in my post, complexity is O(n*log(n)).
Nikita Rybak
@Nikita Thanks - my first implementation took over a minute! But I've got it now :)
Fredrick Pennachi
since N is relatively low all , find all the primes which are `2,3,5,7,11,13,17,19` and multiply them together with multiplicity of each prime `p` being `floor( log_p(20) )` which is 3 for p=2 and 2 for p=3 and 1 for p > 3. Runtime complexity of O(1) :)
ldog
@ldog If N is limited, complexity is always O(1): whole 'complexity' concept makes sense only if argument can grow infinitely. So, my solution is O(1), Matt's solution is O(1), "calculate it all on paper" solution is O(1) too :)
Nikita Rybak
@ldog And multiplier 2 have to be used four times, not three, btw.
Nikita Rybak