Project Euler: Problem 4

If you been following me the last three times I've done this, then you really don't need any introductions.

Problem four is as follows:
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.

And my results in the usual three languages are:
Hasekell:

  1. module Main where
  2.  
  3. import Data.List
  4.  
  5. --Stole numberToList code from:
  6. --http://www.rhinocerus.net/forum/lang-functional/95473-converting-number-list-haskell.html
  7. numberToList = reverse . unfoldr (\x -> if x == 0 then Nothing else let (a,b) = x `quotRem` 10 in Just (b,a))
  8.  
  9. is_palimdrome number = num_list == reverse num_list
  10. where
  11. num_list = numberToList number
  12.  
  13. main :: IO ()
  14. main = print . maximum . filter is_palimdrome $ zipWith (*) y z
  15. where y = [1000,999..100]
  16. z = [1000,999..100]

Python:

  1. #!/usr/bin/python
  2.  
  3. def int_to_list(number):
  4. return map(int, str(number))
  5.  
  6. def is_palindrome(number):
  7. local_list = int_to_list(number)
  8. return local_list == list(reversed(local_list))
  9.  
  10. if __name__ == "__main__":
  11. second_list = first_list = list(reversed(range(100,1000+1)))
  12. prod_set = map(lambda i,j: i*j, first_list, second_list)
  13.  
  14. print "%s" % max(filter(is_palindrome,prod_set))

And finally, Perl:

  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use warnings;
  5. use List::MoreUtils qw(pairwise);
  6.  
  7. sub is_palimdrone
  8. {
  9. my ($number) = @_;
  10.  
  11. my @digits = split(//, $number);
  12. my @reversed_digits = reverse(@digits);
  13.  
  14. for (my $i = 0; $i < @digits; $i++)
  15. {
  16. return 0 if $digits[$i] != $reversed_digits[$i];
  17. }
  18.  
  19. return 1;
  20. }
  21.  
  22. my @two = my @one = reverse((1..1000));
  23.  
  24. my @join = pairwise { $a * $b } @one, @two;
  25.  
  26. foreach(@join)
  27. {
  28. if ( is_palimdrone($_))
  29. {
  30. print "$_\n";
  31. last;
  32. }
  33. }

Run Times
Haskell: 0m0.034s
Python: 0m0.060s
Perl: 0m0.166s

For anyone that is not aware, haskell should win this statistic every time. Out of the three languages its the only one that is compiled. If anyone knows of a way to run haskell interpretively, and without using ghci, please let me know. I've tried looking on the internets for this piece of information, but have come up short.

I am still open to code suggestions or improvements. I have found these to be very helpful and useful. So thank you to everyone that has said something before.

UPDATE
So here is the new code that fixes the problem of my algo before. I'm leaving the old up just to future readers aren't confused.

Thanks goes out to Jeremiah, Tom.B, Juster, and Guillaume for the code ideas used to fix the mistakes in the code above. Thanks guys!

Haskell:

  1. module Main where
  2.  
  3. import Data.List
  4.  
  5. --Stole numberToList code from:
  6. --http://www.rhinocerus.net/forum/lang-functional/95473-converting-number-list-haskell.html
  7. numberToList = reverse . unfoldr (\x -> if x == 0 then Nothing else let (a,b) = x `quotRem` 10 in Just (b,a))
  8.  
  9. is_palimdrome number = num_list == reverse num_list
  10. where
  11. num_list = numberToList number
  12.  
  13. main :: IO ()
  14. main = print . maximum $ [ x * y | x <- nums, y <- nums, is_palimdrome (x * y)]
  15. where nums = [1000,999..100]

Python:
  1. #!/usr/bin/python
  2.  
  3. def int_to_list(number):
  4. return map(int, str(number))
  5.  
  6. def is_palindrome(number):
  7. local_list = int_to_list(number)
  8. return local_list == list(reversed(local_list))
  9.  
  10. if __name__ == "__main__":
  11. print "%s" % max([x * y for x in range(1000,100, -1) \
  12. for y in range(1000,100,-1) \
  13. if is_palindrome(x * y)])

Perl:
  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use warnings;
  5. use List::Util qw(max);
  6.  
  7. sub is_palimdrone
  8. {
  9. my ($number) = @_;
  10.  
  11. my @digits = split(//, $number);
  12. my @reversed_digits = reverse(@digits);
  13.  
  14. for (my $i = 0; $i < @digits; $i++)
  15. {
  16. return 0 if $digits[$i] != $reversed_digits[$i];
  17. }
  18.  
  19. return 1;
  20. }
  21.  
  22. my @two = my @one = reverse((100..999));
  23. my @three;
  24.  
  25. for my $one (@one)
  26. {
  27. for my $two (@two)
  28. {
  29. my $three = $two * $one;
  30. next unless is_palimdrone($three);
  31. push @three, $three;
  32. }
  33. }
  34.  
  35. print max(@three);

Project Euler: Problem 3

OK, next installment of this. :)

The problem is stated as such:
The prime factors of 13195 are 5, 7, 13 and 29.

What is the largest prime factor of the number 600851475143 ?

Haskell:

  1. module Main where
  2.  
  3. factors count top_number
  4. | count >= top_number = []
  5. | zero_mod count = count : new_top: factors (count + 2) new_top
  6. | otherwise = factors (count + 2) top_number
  7. where new_top = round . fromIntegral $ top_number `div` count
  8.  
  9. zero_mod divisor
  10. | divide == 0 = True
  11. | otherwise = False
  12. where divide = mod 600851475143 divisor
  13.  
  14. --prime :: Integer -> Integral -> Bool
  15. prime divisor divided
  16. | divided == 1 = True
  17. | divisor >= sqrt_divided = True
  18. | mod divided divisor == 0 = False
  19. | otherwise = next_prime
  20. where next_prime = prime (divisor + 2) divided
  21. sqrt_divided = round . sqrt . fromIntegral $ divided
  22.  
  23. is_prime :: Integer -> Bool
  24. is_prime input = prime 3 input
  25.  
  26. main :: IO ()
  27. main = do
  28. let x = factors 3 600851475143
  29. let y = map is_prime x
  30. putStrLn $ show $ snd $ maximum ( zip y x)

Getting that sqrt function to work took me longer to figure out than I want to admit. I was having the hardest time getting the numeric types to play nice. I finally broke down and asked the haskell-beginners email list to get the answer.

Python:

  1. #!/usr/bin/python
  2.  
  3. import math
  4.  
  5. top_number = 600851475143
  6.  
  7. def zero_mod(divisor):
  8. if top_number % divisor == 0:
  9. return True
  10. else:
  11. return False
  12.  
  13. def is_prime(divided):
  14. divisor = 3
  15. sqrt_divided = math.sqrt(divided)
  16. if divided == 1:
  17. return True
  18. else:
  19. while divisor <= sqrt_divided:
  20. if divided == divisor:
  21. return True
  22. elif divided % divisor == 0:
  23. return False
  24. else:
  25. divisor += 2
  26. return True
  27.  
  28. def main():
  29. count = 3
  30. go_to = top_number
  31.  
  32. first_list =[]
  33.  
  34. while count <= go_to:
  35. if zero_mod(count):
  36. first_list.append(count)
  37. go_to = top_number / count
  38. first_list.append(go_to)
  39.  
  40. count += 2
  41.  
  42. second_list = map(is_prime, first_list)
  43. print "%s" % max(zip(second_list, first_list))[-1]
  44.  
  45.  
  46. if __name__ == "__main__":
  47. main()

And finally Perl:

  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6. my $top_number = 600851475143;
  7.  
  8. sub is_prime
  9. {
  10. my ($divided) = @_;
  11. return 1 if ($divided == 1);
  12.  
  13. my $divisor = 3;
  14. my $sqrt_divided = sqrt($divided);
  15.  
  16. while($divisor <= $sqrt_divided)
  17. {
  18. return 0 unless ($divided % $divisor);
  19. $divisor += 2;
  20. }
  21.  
  22. 1;
  23. }
  24.  
  25. my @f;
  26. my $new_top = $top_number;
  27.  
  28. for(my $i = 3; $i <= $new_top; $i += 2)
  29. {
  30. unless ($top_number % $i)
  31. {
  32. if (is_prime($i))
  33. {
  34. push @f, $i;
  35. }
  36. }
  37. $new_top = $top_number / $i;
  38. }
  39.  
  40. print $f[-1];

Props goes out to zloyrusski who helped me figure out a major hang up with Perl on this one. The for loop idea was his,though I really diverted from his answer. Goes to show you how much two people really can think differently. Hey Zloyrusski, is this Perl code looking better? ;) As always, I'm open to constructive criticism.

--UPDATES--
1) Code has been redone to fix the error talked about by agf. I find it a little amusing that I still get the same answer though.
2) I gotta start using less languages to do this in. If I make a mistake I've gotta change & test three different versions.
3) Times ( as requested by Caleb):
Haskell: 0.004s
Python: 0.205s
Perl : 0.136s
4) More props for zloyrusski for the division algorithm.

Project Euler, Problem 2

I've got problem #2 in the bag.

Problem #2 goes like this:
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, ...

Find the sum of all the even-valued terms in the sequence which do not exceed four million.

And my code goes as follows:
Haskell:

  1. --fibinaci :: (Num a) => a -> a -> [a]
  2. fibinaci a b
  3. | sum' > 4000000 = []
  4. | otherwise = sum' : fibinaci b sum'
  5. where sum' = a + b
  6.  
  7. problem2 = sum $ filter (even) (fibinaci 0 1)

Python:
  1. #!/usr/bin/python
  2.  
  3. def fibinaci_list( in_list, input1, input2):
  4. flip = True
  5. while ( input1 + input2 < 4000000):
  6. if( flip == True):
  7. input1 = input1 + input2
  8. in_list.append(input1)
  9. flip = False
  10. else:
  11. input2 = input1 + input2
  12. in_list.append(input2)
  13. flip = True
  14.  
  15. def even(n):
  16. if n % 2 == 0:
  17. return True
  18. else:
  19. return False
  20.  
  21.  
  22. def main():
  23. first_list = []
  24. fibinaci_list(first_list, 0, 1)
  25. second_list = filter(even, first_list)
  26. print "%s" % (sum(second_list))
  27.  
  28. if __name__ == "__main__":
  29. main()

And finally, Perl:
  1. #!/usr/bin/perl
  2.  
  3. my $total = 0;
  4. my $count1 = 0;
  5. my $count2 = 1;
  6. my $flip = 1;
  7.  
  8. while( $count2 + $count1 < 4000000)
  9. {
  10. if ( $flip == 1)
  11. {
  12. $count1 += $count2;
  13. if ( $count1 % 2 == 0)
  14. {
  15. $total += $count1;
  16. }
  17. $flip = 0;
  18. }
  19. else
  20. {
  21. $count2 += $count1;
  22. if ( $count2 % 2 == 0)
  23. {
  24. $total += $count2;
  25. }
  26. $flip = 1;
  27. }
  28. }
  29.  
  30. print $total;

Originally, I tried to copy the Python algorithm to Perl, using an array instead of a list. That didn't work. The program would always fail due to out of memory errors. To solve this problem I changed the program to work without using arrays and just took the whole fibinaci function out and put it into main.

As always, constructive comments for the code are welcomed.

Project Euler: Problem 1

So I'll admit it, I'm more than acceptably late to this party. OJ started working on these problems years ago, while I was still coding away on other stuff at school. Now that I'm not in school and needing a challenge I'm doing the best I can to tackle the problems at Project Euler. Since I'm also trying to pick up Haskell, this makes for a good way to learn the language. This isn't my first time using a Functional Programming language. But the last time I tried, it was forced upon me at school with inadequate assistance and the whole experience left a bad taste in my mouth. I'm glad that getting over the bad experience and learning something new at the same time.

I've started keeping a github repo with my solutions for the various problems. If anyone is interested in commenting on my code please do so. I welcome all constructive criticism.

To start this thing off; problem one reads,
“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.”

Being this one was simple. I coded it up in Haskell, Python, and Perl.
Haskell:

  1. problem1 = sum $ filter (\x -> mod x 3 == 0 || mod x 5 == 0) [1..1000]
  2. problem1' = sum $ filter (\x -> mod x 3 == 0 || mod x 5 == 0) [1..999]

Python:
  1. #!/usr/bin/python
  2.  
  3. def threeorfive(n):
  4. if ( n % 3 == 0 or n % 5 == 0):
  5. return True
  6. else:
  7. return False
  8.  
  9. def main():
  10. first_list = range(1,1000)
  11. second_list = filter(threeorfive, first_list)
  12. print "%s" % (sum(second_list))
  13.  
  14. if __name__ == "__main__":
  15. main()

Perl:
  1. #!/usr/bin/perl
  2.  
  3. my $count = 0;
  4. my $total = 0;
  5.  
  6. while ( $count < 1000)
  7. {
  8. if ( $count % 3 == 0 or $count % 5 == 0)
  9. {
  10. $total += $count;
  11. }
  12.  
  13. $count++;
  14. }
  15.  
  16. print $total;

One thing that is nice about doing this in different languages, is that you get to become aware of the differences between some of those languages. For instance in Python the range function works a little differently than I expected. I was expecting an inclusive range function, one in which the 10 is included in the list. But that is now how Python's range works. It gives me 10 numbers, starting with 1, the end result is a list ending in 9. It's not a big deal and easily fixable, but just not something I was expecting. That is why the Haskell code has to functions in it. Just to verify that the Python code was correct.

I'll be posting more answers as I complete them. So expect to see some random posts with Euler solutions in them.

Syndicate content