简体   繁体   中英

Finding the largest palindrome product of two 3-digit numbers: what is the error in logic?

I thought of solving this problem in the following way: start with two variables with value 999, multiplying one by another in a loop that decrements one or the other until a palindrome is found. The code is this:

def is_palindrome(n):
  if str(n) == str(n)[::-1]:
    return True
  else:
    return False

def largest_palindrome_product_of_3_digit():
  x = 999
  y = 999
  for i in reversed(range(x + y + 1)):
    if is_palindrome(x * y):
      return x * y
    if i % 2 == 0:
      x -= 1
    else:
      y -= 1

The result of my method is 698896, while the correct result is 906609. Could you point me where my logic is incorrect?

Here are a couple of hints:

  1. If n=y*x is any number in the range(600000, 700000) (for example) with y<=x, and x<1000, what's the smallest possible value of x?
  2. If n is a palindromic number, both its first and last digit are 6, so what does that imply about the last digits of x & y?

Now generalize and figure out an efficient algorithm. :)

I've never done this problem before, but I just coded a reasonably fast algorithm that's around 2000 times faster than a brute-force search that uses

for x in xrange(2, 1000): 
    for y in xrange(2, x+1):
        n = y*x
        #etc

According to timeit.py, the brute-force algorithm takes around 1.29 seconds on my old machine, the algorithm I hinted at above takes around 747 microseconds.


Edit

I've improved my bounds (and modified my algorithm slightly) and brought the time down to 410 µsec. :)

To answer your questions in the comment:

Yes, we can start x at the square root of the beginning of the range, and we can stop y at x (just in case we find a palindromic square).

What I was getting at with my 2nd hint is that for x=10*I+i, y=10*J+j, we don't need to test all 81 combinations of i and j, we only need to test the ones where (i*j)%10 equals the digit we want. So if we know that our palindrome starts and ends with 9 then (i, j) must be in [(1, 9), (3, 3), (7, 7), (9, 1)].

I don't think I should post my actual code here; it's considered bad form on SO to post complete solutions to Project Euler problems. And perhaps some SO people don't even like it when people supply hints. Maybe that's why I got down-voted...

You're missing possible numbers.

You're considering O(x+y) numbers and you need to consider O(x * y) numbers. Your choices are, essentially, to either loop one of them from 999, down to 1, then decrement the other and...

Simple demonstration:

>>> want = set()
>>> for x in [1, 2, 3, 4, 5]:
...   for y in [1, 2, 3, 4, 5]:
...     want.add(x * y)
... 
>>> got = set()
>>> x = 5
>>> y = 5
>>> for i in reversed(range(x + y + 1)):
...   got.add(x * y)
...   if i % 2:
...     x -= 1
...   else:
...     y -= 1
... 
>>> want == got
False

Alternatively, you do know the top of the range (999 * 999) and you can generate all palindromic numbers in that range, from the highest to the lowest. From there, doing a prime factorization and checking if there's a split of the factors that multiply to two numbers in the range [100,999] is trivial.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM