Euler problem number #4

前端 未结 14 1872
萌比男神i
萌比男神i 2021-01-03 11:00

Using Python, I am trying to solve problem #4 of the Project Euler problems. Can someone please tell me what I am doing incorrectly? The problem is to Find the larg

相关标签:
14条回答
  • 2021-01-03 11:23

    Wow, this approach improves quite a bit over other implementations on this page, including mine.

    Instead of

    • walking down the three-digit factors row by row (first do all y for x = 999, then all y for x = 998, etc.),

    we

    • walk down the diagonals: first do all x, y such that x + y = 999 + 999; then do all x, y such that x + y = 999 + 998; etc.

    It's not hard to prove that on each diagonal, the closer x and y are to each other, the higher the product. So we can start from the middle, x = y (or x = y + 1 for odd diagonals) and still do the same short-circuit optimizations as before. And because we can start from the highest diagonals, which are the shortest ones, we are likely to find the highest qualifying palindrome much sooner.

    maxFactor = 999
    minFactor = 100
    
    def biggest():
        big_x, big_y, max_seen, prod = 0, 0, 0, 0
    
        for r in xrange(maxFactor, minFactor-1, -1):
            if r * r < max_seen: break
    
            # Iterate along diagonals ("ribs"):
    
            # Do rib x + y = r + r
            for i in xrange(0, maxFactor - r + 1):
                prod = (r + i) * (r - i)
    
                if prod < max_seen: break
    
                if is_palindrome(prod):
                    big_x, big_y, max_seen = r+i, r-i, prod
    
            # Do rib x + y = r + r - 1
            for i in xrange(0, maxFactor - r + 1):
                prod = (r + i) * (r - i - 1)
    
                if prod < max_seen: break
    
                if is_palindrome(prod):
                    big_x, big_y, max_seen = r+i,r-i-1, prod
    
        return big_x, big_y, max_seen
    
    # biggest()
    # (993, 913, 906609)
    

    A factor-of-almost-3 improvement

    Instead of calling is_palindrome() 6124 times, we now only call it 2228 times. And the total accumulated time has gone from about 23 msec down to about 9!

    I'm still wondering if there is a perfectly linear (O(n)) way to generate a list of products of two sets of numbers in descending order. But I'm pretty happy with the above algorithm.

    0 讨论(0)
  • 2021-01-03 11:24

    This is what I did in Java:

    public class Euler0004
    {
        //assumes positive int
        static boolean palindrome(int p)
        {
            //if there's only one char, then it's
            //  automagically a palindrome
            if(p < 10)
                return true;
    
            char[] c = String.valueOf(p).toCharArray();
    
            //loop over the char array to check that
            //  the chars are an in a palindromic manner
            for(int i = 0; i < c.length / 2; i++)
                if(c[i] != c[c.length-1 - i])
                    return false;
    
            return true;
        }
    
    
        public static void main(String args[]) throws Exception
        {
            int num;
            int max = 0;
    
            //testing all multiples of two 3 digit numbers.
            // we want the biggest palindrome, so we
            // iterate backwards
            for(int i = 999; i > 99; i--)
            {
                // start at j == i, so that we
                //  don't calc 999 * 998 as well as
                //  998 * 999...
                for(int j = i; j > 99; j--)
                {
                    num = i*j;
    
                    //if the number we calculate is smaller
                    //  than the current max, then it can't
                    //  be a solution, so we start again
                    if(num < max)
                        break;
    
                    //if the number is a palindrome, and it's
                    //  bigger than our previous max, it
                    //  could be the answer
                    if(palindrome(num) && num > max)
                        max = num;
                }
            }
    
            //once we've gone over all of the numbers
            //  the number remaining is our answer
            System.out.println(max);
    
        }
    }
    
    0 讨论(0)
  • 2021-01-03 11:25

    If your program is running slow, and you have nested loops like this:

    for z in range(100, 1000):
        for y in range(100, 1000):
            for x in range(1, 1000000):
    

    Then a question you should ask yourself is: "How many times will the body of the innermost loop execute?" (the body of your innermost loop is the code that starts with: x = str(x))

    In this case, it's easy to figure out. The outer loop will execute 900 times. For each iteration the middle loop will also execute 900 times – that makes 900×900, or 810,000, times. Then, for each of those 810,000 iterations, the inner loop will itself execute 999,999 times. I think I need a long to calculate that:

    >>> 900*900*999999
    809999190000L
    

    In other words, you're doing your palindrome check almost 810 billion times. If you want to make it into the Project Euler recommended limit of 1 minute per problem, you might want to optimise a little :-) (see David's comment)

    0 讨论(0)
  • 2021-01-03 11:28

    Some efficiency issues:

    1. start at the top (since we can use this in skipping a lot of calculations)
    2. don't double-calculate
    def is_palindrome(n):
        s = str(n)
        return s == s[::-1]
    
    def biggest():
        big_x, big_y, max_seen = 0,0, 0
        for x in xrange(999,99,-1):
            for y in xrange(x, 99,-1):  # so we don't double count   
                if x*y < max_seen: continue  # since we're decreasing, 
                                    # nothing else in the row can be bigger
                if is_palindrome(x*y):
                    big_x, big_y, max_seen = x,y, x*y
    
        return big_x,big_y,max_seen
    
    biggest()
    # (993, 913, 906609)
    
    0 讨论(0)
  • 2021-01-03 11:28

    rather than enumerating all products of 3-digit numbers (~900^2 iterations), enumerate all 6- and 5-digit palyndromes (this takes ~1000 iterations); then for each palyndrome decide whether it can be represented by a product of two 3-digit numbers (if it can't, it should have a 4-digit prime factor, so this is kind of easy to test).

    also, you are asking about problem #4, not #3.

    0 讨论(0)
  • 2021-01-03 11:33

    Here's some general optimizations to keep in mind. The posted code handles all of this, but these are general rules to learn that might help with future problems:

    1) if you've already checked z = 995, y = 990, you don't need to check z = 990, y = 995. Greg Lind handles this properly

    2) You calculate the product of z*y and then you run x over a huge range and compare that value to y*z. For instance, you just calculated 900*950, and then you run x from 1000 to 1M and see if x = 900*950. DO you see the problem with this?

    3) Also, what happens to the following code? (this is why your code is returning nothing, but you shouldn't be doing this anyway)

    x = str(100)
    y = 100
    print x == y
    

    4) If you figure out (3), you're going to be printing a lot of information there. You need to figure out a way to store the max value, and only return that value at the end.

    5) Here's a nice way to time your Euler problems:

    if __name__ == "__main__":
        import time
        tStart = time.time()
        print "Answer = " + main()
        print "Run time = " + str(time.time() - tStart)
    
    0 讨论(0)
提交回复
热议问题