Python's ability to remove items from a List seems to be lacking here; at the very least the code is a little more terse then usual. The remove operation raises an error is the element is not present, so telling it to pass will simply ignore the resulting error. I am sure there is a terser way to represent the Sieve in Python, but the code above emphasizes readable and is comparable to pseudo code, except for the error handling.

The problem with the previous implementation is that it is slow. with a N of 10000 taking about a second, a N of 100000 taking ~101 seconds, and a N of 1000000 uncomfortably heating up my laptop, though it should clock in at about an hour.

Excuse my sloppy Big O notation, but according to Wikipedia, the complexity of the Sieve is O(n(logn)(loglogn)).

The red flag here is the remove call. While I'm not sure how Python implements List.remove, according to the documentation it removes the first instance of the element it is searching for. So the method needs to iterate the list until it finds the element, and then readjust the remainder of the List, which is a costly operation, especially inside a for and while loop. I believe this would add another n to the complexity, O(n^2(logn)(loglogn)). (Edit: please disregard my sloppy Big O notation here, without knowing the implementation details behind the Python List remove operation I can only hazard a guess. We know that the remove operation stops at the first instance of the char, but then the List must be have an element removed, which can vary in cost depending on the data structure used. Analysis of this operation requires Python guru skills that I currently lack.) I am really out of practice with Big O notation, so please correct me if I am wrong here.

It took me awhile to figure out how to get the run time of the sieve down, I eventually went online to try to find a hint of how to improve performance. Someone on the internet recommended replacing the composite numbers with zeros. It is painfully obvious once you see it; get rid of the remove operation altogether. Instead of removing the non-prime (composite) elements, replace them with a placeholder value.

Tuesday, February 9, 2010

I think I am going to abandon any pretense of tackling problems in the proper order. The difficulty varies and the more difficult problems are not only more difficult to solve, but also require more time for the write up.

Sunday, February 7, 2010

I am skipping Problem 3 for now as I want to take my time with the write up. In general I am going to try to make these post more verbose otherwise they aren't very useful to anyone, myself included.

That being said let's take a look at 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 x 99.
Find the largest palindrome made from the product of two 3-digit numbers.

First thing we want to do is generate all the products of two 3-digit numbers. That can done with a fairly simple loop where we multiple ever possible number from 100 x 100 to 999 x 999. I'm starting at 999 because I think there may be a way to optimize the generation loop by only looking at the largest, more on this later. So the way this loop works is, starting both factors, i and j, at 999, count down i and then when it drops below 100, reset it 999 and decrement the other factor, j. So the iterations would go, 999 x 999, 998 x 999, 997 x 999 .... 100 x 999, 999 x 998, etc.

In each each iteration we check to see if the product is a palindrome and if it is we check to see if it is larger then the previous palindrome. This means that by the time our loop ends we have the largest possible palindrome.

Determining if the product is a palindrome is easily expressed in Python;

First thing we do is convert the product n into a string. Once we have that it is easy to reverse the string by using the Python slice(?) operation. The syntax for slice is, start position:end position:value of each step, so what

[::-1]

translates to is, starting at the beginning and ending at the end, go through the string backwards (-1). Once you have the reverse string, you can compare it to the original string and determine if it is a palindrome.

There are ways to improve on this implementation. As I mentioned before, there is probably a way to check to make sure that you are only doing the largest possible factors first, say 900 x 900 to 999 x 999, by structuring the while loop so it goes through all factors in each hundreds place. The palindrome could also be implemented in a way that doesn't use string conversion. That being said, this program runs in about a second and works, so any additional optimization is really not needed in this case. However if you were going to test for the largest palindrome product of two 4-digit numbers, this implementation is slow, taking about 110.63 seconds. The official Project Euler answer has an more optimal solution, but since I looked at it I am not going to post the solution here as my own.

Not much of interest here, aside from noting that writing this problem in Java felt like writing enterprise FizzBuzz. The use of Collections and Integers might be over engineering on my part, but what can I say, I like the way the For Each loop looks.